JPA @ Entity内的Bean注入

是否可以使用Spring的依赖注入将bean注入JPA @ @Entity

我尝试了@Autowire ServletContext,但是,当服务器确实启动成功时,我在尝试访问bean属性时收到NullPointerException。

@Autowired
@Transient
ServletContext servletContext;

您可以使用@Configurable将依赖关系注入到未由Spring容器管理的对象中,如下所述:http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/aop.html#aop -atconfigurable。

正如您现在已经意识到的,除非使用@Configurable和适当的AspectJ编织配置,否则Spring不会将依赖注入到使用new运算符创建的对象中。 事实上,它不会将依赖注入到对象中,除非您从ApplicationContext检索它们,原因很简单,因为它根本不知道它们的存在。 即使你用@Component注解你的实体,实体的实例仍然会由一个new操作执行,无论是你还是像Hibernate这样的框架。 请记住,注释只是元数据:如果没有人解释该元数据,则不会添加任何行为或对正在运行的程序产生任何影响。

ServletContext ,我强烈建议不要将ServletContext注入实体。 实体是您的域模型的一部分,应该与任何传递机制(如基于Servlet的Web传递层)分离。 当它被一个命令行客户端访问或者其他不涉及ServletContext的东西访问时,你将如何使用该实体? 您应该从该ServletContext中提取必要的数据,并将其通过传统的方法参数传递给您的实体。 通过这种方法你将获得更好的设计。


是的,当然可以。 您只需确保实体也注册为Spring托管bean,或者声明性地使用<bean>标记(在某些spring-context.xml中)或通过注释(如下所示)。

使用注释,你可以用@Component标记你的实体(或者一个更具体的@Repository@Repository ,它可以为DAO启用自动异常转换,并且可能会或可能不会干扰JPA)。

@Entity
@Component
public class MyJAPEntity {

  @Autowired
  @Transient
  ServletContext servletContext;
  ...
}

一旦你完成了你的实体,你需要配置他们的包(或者一些祖先包)以供Spring扫描,这样实体就可以作为bean来获取,并且它们的依赖关系会自动连线。

<beans ... xmlns:context="..." >
  ...
  <context:component-scan base-package="pkg.of.your.jpa.entities" />
<beans>

编辑 :(什么最终工作,为什么)

  • 使ServletContext静态。 (删除@Autowired)

    @Transient
    private static ServletContext servletContext;
    
  • 因为JPA正在创建一个单独的实体实例,即不使用Spring托管bean,所以需要共享上下文。

  • 添加@PostConstruct init()方法。

    @PostConstruct
    public void init() {
        log.info("Initializing ServletContext as [" +
                    MyJPAEntity.servletContext + "]");
    }
    
  • 一旦Entity被实例化并引用ServletContext ,它就会触发init() ,如果不是已经注入的话,它会强制注入静态属性。

  • @Autowired移动到一个实例方法,但在里面设置静态字段。

    @Autowired
    public void setServletContext(ServletContext servletContext) {
        MyJPAEntity.servletContext = servletContext;
    }
    
  • 引用我的最后一条评论来回答为什么我们必须雇用这些诡计:

    由于JPA没有使用Spring容器来实例化它的实体,所以没有什么好办法做你想做的事情。 将JPA想象成一个单独的ORM容器,用于实例化和管理实体的生命周期(与Spring完全分离),并且仅基于实体关系进行DI。


    经过很长时间我偶然发现了这个答案,这让我想到了一个优雅的解决方案:

  • 将您需要的所有@Transient @Autowired字段添加到您的实体中
  • 用这个自动布线字段创建一个@Repository DAO: @Autowired private AutowireCapableBeanFactory autowirer;
  • 从你的DAO中,从DB获取实体后,调用这个自动装配代码: String beanName = fetchedEntity.getClass().getSimpleName(); autowirer.autowireBean(fetchedEntity); fetchedEntity = (FetchedEntity) autowirer.initializeBean(fetchedEntity, beanName); String beanName = fetchedEntity.getClass().getSimpleName(); autowirer.autowireBean(fetchedEntity); fetchedEntity = (FetchedEntity) autowirer.initializeBean(fetchedEntity, beanName);
  • 您的实体随后可以像任何@Component一样访问自动布线字段。

    链接地址: http://www.djcxy.com/p/44085.html

    上一篇: Bean injection inside a JPA @Entity

    下一篇: JPA versus JPA: What's the difference?