@ApplicationScoped CDI bean and @PersistenceContext - is this safe?

前端 未结 2 1340
Happy的楠姐
Happy的楠姐 2021-02-01 03:48

Is it safe to do something like this with CDI?

@Named
@ApplicationScoped
public class DAO {

   @PersistenceContext
   private EntityManager entityManager;

}
         


        
2条回答
  •  深忆病人
    2021-02-01 04:43

    I'm pretty sure that in this case CDI does not create a contextual proxy for the entity manager. After all, what scope would it be in? You may want something akin to a hypothetical @ThreadScoped or just @RequestScoped, but @PersistenceContext is not a CDI annotation and CDI does not modify its semantics.

    So what's happening here is the Java EE 6 platform "managed bean" injection, which is similar to injecting the entity manager in a Servlet. Both cases give you an instance that is not thread-safe to use directly.

    It looks like it's safe to use with @Stateless, for instance - but I'm not sure if that's because of the way @Stateless works, or because of something intrinsic to @PersistenceContext itself.

    It's because of the way @Stateless works. Every request (call) to a method on a stateless bean is routed by the container to a unique instance. The container guarantees that no two threads are ever active in the same bean.

    With CDI you can get a similar effect per request by encapsulating the entity manager in a request scoped bean and injecting that into the application scoped one:

    import javax.enterprise.context.RequestScoped;
    import javax.persistence.EntityManager;
    import javax.persistence.PersistenceContext;
    
    @RequestScoped
    public class EntityManagerProvider {
    
        @PersistenceContext
        private EntityManager entityManager;
    
        public EntityManager getEntityManager() {
            return entityManager;
        }
    
    }
    

    Inject this into the bean where you previously injected the entity manager:

    @Named
    @ApplicationScoped
    public class DAO {
    
       @Inject
       private EntityManagerProvider entityManagerProvider;
    
    }
    

    This will give you a unique entity manager per request. You can easily turn this into a producer method as well, so you won't have to call getEntityManager() on the injected provider.

提交回复
热议问题