Actualmente estoy trabajando en una aplicación Java EE 7 Batch API y me gustaría que el ciclo de vida de uno de mis CDI Bean esté relacionado con el trabajo actual. En realidad, me gustaría que este bean tuviera un alcance @JobScoped (pero no existe en la API). También me gustaría que este frijol sea inyectable en cualquiera de mis clases de trabajos.

Al principio, quería crear mi propio alcance @JobScoped, con un JobScopedContext, etc. Pero luego se me ocurrió la idea de que Batch API tiene el bean JobContext con una identificación de trabajo única por frijol.

Así que me pregunto si podría administrar el ciclo de vida de mi bean con ámbito de trabajo con este JobContext.

Por ejemplo, tendría mi bean que quiero que tenga un ámbito de trabajo:

@Alternative
public class JobScopedBean
{
   private String m_value;

   public String getValue()
   {
      return m_value;
   }

   public void setValue(String p_value)
   {
      m_value = p_value;
   }
}

Entonces tendría el productor de este bean que devolverá el JobScopedBean asociado al trabajo actual (gracias al JobContext que es único por trabajo)

public class ProducerJobScopedBean
{

  @Inject
  private JobContext m_jobContext;// this is the JobContext of Batch API

  @Inject
  private JobScopedManager m_manager;

  @Produces
  public JobScopedBean getObjectJobScoped() throws Exception
  {
      if (null == m_jobContext)
     {
         throw new Exception("Job Context not active");
      }

      return m_manager.get(m_jobContext.getExecutionId());
   }
}

Y el administrador que tiene el mapa de mi JobScopedBean:

@ApplicationScoped
public class JobScopedManager
{
   private final ConcurrentMap<Long, JobScopedBean> mapObjets = new   ConcurrentHashMap<Long, JobScopedBean>();

   public JobScopedBean get(final long jobId)
   {
      JobScopedBean returnObject = mapObjets.get(jobId);
      if (null == returnObject)
      {
         final JobScopedBean ajout = new JobScopedBean();
         returnObject = mapObjets.putIfAbsent(jobId, ajout);

         if (null == returnObject)
         {
            returnObject = ajout;
         }
      }
      return returnObject;
   }

Por supuesto, gestionaré la destrucción del JobScopedBean al final de cada trabajo (a través de un JobListener y un CDI Event).

¿Puedes decirme si me equivoco con esta solución?

Me parece correcto, pero ¿tal vez me falta algo?

¿Puede haber una mejor manera de manejar esto?

Gracias.

1
Rouliboy 15 ene. 2017 a las 15:41

1 respuesta

La mejor respuesta

Así que todo se reduce a la creación de beans de ámbito @Dependent que se basan en un trabajo en la creación. Funciona bien para beans con una vida útil más corta que el trabajo, por lo que solo para los ámbitos estándar @Dependent (@ Request / @ Session / @ Converstion puede estar bien, pero no se aplica aquí).

Causará problemas para otros ámbitos, especialmente @ ApplicationScoped / @ Singleton. Si inyecta JobScopedBean en uno de ellos. Es posible que tenga (des) suerte de tener un trabajo activo cuando los necesite la primera vez, pero los beans siempre se adjuntarán a ese trabajo inicial (los beans de alcance @Dependent no están pseudoscópicos, por lo que no crearán proxies para obtener la instancia contextual)

Si desea algo así, cree un ámbito aduanero.

1
k5_ 18 ene. 2017 a las 00:51
Gracias @ k5_. Este fue el punto que me perdí, ¡qué vergüenza! Por supuesto, el problema está en los beans @ApplicationScoped (de hecho, incluso inyectar un JobContext en el bean @ApplicationScoped solucionará los problemas, ya que el bean inyectado dependerá del bean @ApplicationScoped). Gracias por señalar el problema en mi solución, sabía que algo andaba mal pero no podía resolverlo.
 – 
Rouliboy
18 ene. 2017 a las 11:59
Probaré el alcance CDI personalizado, que parece la única forma de lograrlo.
 – 
Rouliboy
18 ene. 2017 a las 13:43