Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring JPA@实体内的Bean注入_Spring_Spring Mvc_Jpa - Fatal编程技术网

Spring JPA@实体内的Bean注入

Spring JPA@实体内的Bean注入,spring,spring-mvc,jpa,Spring,Spring Mvc,Jpa,是否可以使用Spring的依赖项注入将bean注入JPA@实体 我尝试@Autowire ServletContext,但当服务器成功启动时,我在尝试访问bean属性时收到一个NullPointerException @Autowired @Transient ServletContext servletContext; 是的,当然可以。您只需要确保实体也注册为Spring管理的bean,可以使用标记(在某些Spring context.xml中)声明性地注册,也可以通过如下所示的注释注册 使

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

我尝试@Autowire ServletContext,但当服务器成功启动时,我在尝试访问bean属性时收到一个NullPointerException

@Autowired
@Transient
ServletContext servletContext;

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

使用注释,您可以使用
@Component
(或更具体的原型
@Repository
,该原型支持DAO的自动异常转换,并且可能会干扰JPA,也可能不会干扰JPA)

一旦您为您的实体完成了这项工作,您就需要配置它们的包(或某个祖先包)以供Spring扫描,这样实体就可以作为bean被提取,它们的依赖关系就可以自动连接

<beans ... xmlns:context="..." >
  ...
  <context:component-scan base-package="pkg.of.your.jpa.entities" />
<beans>
由于JPA正在创建一个单独的实体实例,即不使用Spring托管bean,因此需要共享上下文

  • 添加@PostConstruct
    init()
    方法

    @PostConstruct
    public void init() {
        log.info("Initializing ServletContext as [" +
                    MyJPAEntity.servletContext + "]");
    }
    
一旦实体被实例化并通过引用内部的
ServletContext
触发
init()

  • @Autowired
    移动到实例方法,但在其中设置静态字段

    @Autowired
    public void setServletContext(ServletContext servletContext) {
        MyJPAEntity.servletContext = servletContext;
    }
    
下面引用我的最后一句话来回答为什么我们要使用这些恶作剧:

因为JPA不使用Spring容器来实例化它的实体,所以没有很好的方法来做您想要做的事情。将JPA视为一个单独的ORM容器,它实例化和管理实体的生命周期(与Spring完全分离),并且只基于实体关系进行DI


您可以使用
@Configurable
将依赖项注入到Spring容器未管理的对象中,如下所述:

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


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

经过很长一段时间,我无意中发现了一个让我想到了一个优雅的解决方案:

  • 将所需的所有@Transient@Autowired字段添加到实体中
  • 使用此自动连接字段创建@Repository DAO:
    
    @自动连线专用自动连线功能BeanFactory自动连线器;
    
  • 从DAO中,从DB获取实体后,调用以下自动连接代码:
    
    字符串beanName=fetchedEntity.getClass().getSimpleName();
    autowire.autowireBean(fetchedEntity);
    fetchedEntity=(fetchedEntity)autowire.initializeBean(fetchedEntity,beanName);
    

然后,您的实体将能够像任何@Component一样访问自动连接字段。

不幸的是,在将
@Component
添加到实体和
添加到
app config.xml
后,
servletContext
仍然为空。请将其设置为静态<代码>私有静态ServletContext ServletContext
如果它仍然是
null
则通过定义
@PostConstruct public void init(){log.info(“将ServletContext初始化为[“+MyJPAEntity.ServletContext+”]);}
希望这会有所帮助。将它设置为
静态后仍然是null。我想我对
@PostConstruct
的功能感到困惑。
@PostConstruct
一旦实体被实例化,就会触发init(),并通过引用其中的servletContext,强制为创建的实例注入(现在是静态的)属性<代码>静态I/CODE >以确保它是共享的,因为JPA正在创建一个单独的实体实例,即不使用Spring托管bean。当您必须在JPA实体中注入其他bean时,我认为它是代码气味,我认为最好重新考虑重新设计实体及其周围的(包私有)类,这两个问题的答案都是一个有用的SO线程的完美例子(我两个都投了赞成票)。虽然@RaviThapliyal下面的答案提供了一种实现结果的方法,但您的答案提供了背景知识(对我来说,这是一种“啊哈”——帮助我将过去几周读到的关于Spring的DI的所有理论信息转化为实际应用知识的体验)。在我看来,这样的帖子实在是太多了,因为它们确实教会了你一些东西(而且往往不会为你赢得太多的声誉)。@sthzg当我情绪低落,需要重新找回信心时,我会回到这里,阅读你的评论。谢谢。在将EntityManager注入EntityListener时,我也遇到了同样的问题,并找到了解决方案
@PostConstruct
public void init() {
    log.info("Initializing ServletContext as [" +
                MyJPAEntity.servletContext + "]");
}
@Autowired
public void setServletContext(ServletContext servletContext) {
    MyJPAEntity.servletContext = servletContext;
}