@PersistenceContext不适用于参数.如何通过构造函数注入EntityManager



使用构造函数注入是一种最佳实践。然而,我无法用@PersistenceContext实现这一点。

我想拥有以下构造函数:

private final EntityManager entityManager;
@Autowired
public MyService(@PersistenceContext EntityManager entityManager) {
this.entityManager = entityManager;
}

但我不能,因为@PersistenceContext只适用于TYPEMETHODFIELD

Q:如何通过构造函数注入管理的容器EntityManager

您似乎在使用spring,因此您的解决方案将相当简单:

@Component
@Scope("prototype")
public class MyPersistenceContainer
{
@PersistenceContext
private EntityManager em;
public EntityManager getEntityManager()
{
return em;
}
}

现在,您可以简单地在构造函数中注入此类的实例,它将始终持有有效的EntityManager(因为bean作用域)。请注意:在web环境中,您可能应该使用@SessionScope甚至@RequestScope而不是原型,这将节省资源


但有一些事情需要考虑:

当使用对bean有依赖关系的singleton作用域bean时范围为原型,请注意依赖关系在实例化时解决。这意味着,如果您依赖将原型作用域bean注入到单例作用域bean,即品牌将实例化新的原型bean,然后注入依赖项进入singleton bean。。。但仅此而已。完全相同的原型实例将是提供给singleton作用域的bean,如果这是您想要的,那么这很好。

然而,有时您真正想要的是单例作用域bean能够获得原型作用域bean在运行时一次又一次。因为如果只是依赖注入一个原型作用域的bean就没有用了到您的singleton bean中,因为如上所述当Spring容器实例化singleton时发生一次bean及其依赖关系的解析和注入。如果你在需要获得(原型)的全新实例的场景在运行时,bean一次又一次地引用标题为第4.3.7节"方法注入">

因此,如果您想将"实体管理器容器bean"注入到singleton beans中(这是默认范围),请查看https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-工厂法注射


正确设置作用域非常重要,否则可能会出现(并且将出现)数据库不一致、死锁或更糟的情况

使用Spring Data是可能的。但是,如果您出于某种原因不想在项目中使用Spring Data(例如,您只是想让遗留项目变得更好一点),您可以创建以下FactoryBean,通过构造函数注入使EntityManager可注入:

/**
* Makes the {@link EntityManager} injectable via <i>@Autowired</i>,
* so it can be injected with constructor injection too.
* (<i>@PersistenceContext</i> cannot be used for constructor injection.)
*/
public static class EntityManagerInjectionFactory extends AbstractFactoryBean<EntityManager> {
@PersistenceContext
private EntityManager entityManager;
@Override
public Class<?> getObjectType() {
return EntityManager.class;
}
@Override
protected EntityManager createInstance() {
return entityManager;
}
}

请注意,因为我们在内部使用@PersistenceContext注释,所以返回的EntityManager将是一个适当的线程安全代理,因为它将在使用字段注入时直接注入。

最新更新