2010-03-08 11 views
6

Tenemos algunos beans EJB sin estado JavaEE5 que pasan el EntityManager inyectado a sus ayudantes.¿Está bien pasar EntityManagers inyectados a las clases auxiliares de beans de EJB y usarlos?

¿Esto es seguro? Hasta ahora funcionaba bien, pero descubrí un documento de Oracle que indica que su implementación de EntityManager es segura para subprocesos. Ahora me pregunto si la razón por la que no tuvimos problemas hasta ahora, fue solo porque la implementación que estábamos usando resultó ser segura (usamos Oracle).

@Stateless 
class SomeBean { 
    @PersistenceContext 
    private EntityManager em; 

    private SomeHelper helper; 

    @PostConstruct 
    public void init(){ 
     helper = new SomeHelper(em); 
    } 

    @Override 
    public void business(){ 
     helper.doSomethingWithEm(); 
    } 

} 

En realidad tiene sentido .. Si EntityManager es thread-insegura, un contenedor tendría que hacer

inercept business() 
this.em = newEntityManager(); 
business(); 

que no se propagará a sus clases de ayuda.

Si es así, ¿cuál es la mejor práctica en este tipo de situación? ¿Al pasar EntityManagerFactory en lugar de EntityManager?

EDIT: This question es muy interesante por lo que si usted está interesado en esta pregunta, es probable que desee echa un vistazo a éste, también:

EDIT: Más información. Instancias ejb3.0 spec

4.7.11 no reentrante El recipiente debe asegurarse de que sólo uno hilo puede estar ejecutando una instancia en cualquier momento. Si una solicitud de cliente llega para una instancia, mientras que la instancia se ejecutando otra solicitud, el contenedor puede tirar la javax.ejb.ConcurrentAccessException a el segundo cliente [24]. Si se utiliza la vista de cliente EJB 2.1 , el contenedor puede lanzar el java.rmi.RemoteException a la segunda solicitud si el cliente es un cliente remoto , o la javax.ejb.EJBException si el cliente es un local de cliente. [25] Tenga en cuenta que un objeto de sesión está destinado a admitir solo un único cliente. Por lo tanto, sería un error de aplicación si dos clientes intentaron invocar el mismo objeto de sesión . Una implicación de esta regla es que una aplicación no puede realizar llamadas de bucle invertido a una instancia de bean de sesión .

Y,

4.3.2 Inyección de dependencias Un bean de sesión puede utilizar la inyección de dependencias mecanismos para adquirir referencias a recursos u otros objetos en su entorno (ver Capítulo 16, "Enterprise Bean Environment"). Si un grano sesión hace uso de la inyección de dependencias , el contenedor inyecta estas referencias después de la instancia del bean es creado, y antes de cualquier negocio métodos se invocan en el frijol ejemplo.Si se declara una dependencia en el SessionContext, o si la clase de bean implementa la interfaz opcional SessionBean (consulte la Sección 4.3.5), el SessionContext también se inyecta en este momento. Si la inyección de la dependencia falla, la instancia del bean es descartada. Bajo la API EJB 3.0, la clase de bean puede adquirir la interfaz SessionContext a través de la inyección de dependencia sin tener que implementar la interfaz SessionBean. En este caso, la anotación Resource (o el elemento descriptor resource-env-ref deployment ) se usa para denotar la dependencia del bean en el SessionContext. Consulte el Capítulo 16, "Enterprise Bean Environment".

+0

Ahora bien, esto es interesante "La especificación EJB 3.1 dice que la inyección de dependencia solo se realiza en el momento de la construcción, de modo que todos los que llaman de MyRepository usarían la misma instancia de EntityManager". : http: //stackoverflow.com/questions/2015184/how-is-threadsafty-guranteed-with-persistencecontext –

+0

FYI, lea también el § 4.1.13, o vea esta respuesta http: // stackoverflow.com/questions/1954137/how-is-that-instance-pooling-with-ejbs-can-improve-performance/1954229 # 1954229. De modo que se accederá a cada ayudante por un hilo a la vez. – ewernli

+0

Este es exactamente el patrón que estaba pensando en implementar. Estoy muy feliz de ver que es posible. Buena publicación. Gracias. – b3bop

Respuesta

2

Usé un patrón similar, pero el helper se creó en @PostConstruct y el administrador de entidad inyectado se pasó en el constructor como parámetro. Cada instancia de EJB tenía su propio asistente y se garantizaba la seguridad de los hilos en ese momento.

También tuve una variante donde no se inyectó el administrador de entidades (porque el EJB no lo estaba usando del todo), por lo que el ayudante debe buscarlo con InitialContext. En este caso, el contexto de persistencia debe todavía ser "importados" en el EJB padre con @PersistenceContext:

@Stateless 
@PersistenceContext(name="OrderEM") 
public class MySessionBean implements MyInterface { 
    @Resource SessionContext ctx; 
    public void doSomething() { 
    EntityManager em = (EntityManager)ctx.lookup("OrderEM"); 
    ... 
    } 
} 

Pero en realidad es más fácil de inyectar (incluso si el EJB no lo utiliza) que mirar hacia arriba , especialmente para la capacidad de prueba.

Pero para volver a su pregunta principal, creo que el administrador de entidades que se inyecta o se busca es un contenedor que lo reenvía al administrador de entidad activo subyacente que está vinculado a la transacción.

Espero que ayude.

EDITAR

La sección § § 3.3 y 5.6 en la especificación cubrir un poco el tema.

+0

¡Gracias, me alegra saber que no tenemos que investigar nuestro código de producción! –

2

He estado usando métodos ayudante y pasó la EntityManager allí, y es perfectamente bien.

Así que recomendaría pasarlo a los métodos cuando sea necesario, o hacer que el ayudante sea un bean, inyectarlo (usando @EJB) e inyectar allí también el EntityManager.

+0

Los métodos de ayuda suenan muy simples y buenos. ¡Gracias! –

0

Bueno, personalmente, no me gustaría tener que pasar el Administrador de la entidad a todos mis POJO en mis constructores o métodos. Especialmente para programas no triviales donde el número de POJO es grande.

Intentaré crear POJOs/HelperClasses que se ocupen de las entidades devueltas por EntityManager, en lugar de utilizar directamente el entitymanager.

Si no es posible, creo que crearía un nuevo EJB Bean.

Cuestiones relacionadas