我正在开发一个简单的Java EE应用程序。
我有这样的课程:
import javax.annotation.PostConstruct;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
@Stateless
public class BlogEntryDao {
EntityManager em;
@PostConstruct
public void initialize(){
EntityManagerFactory emf = Persistence.createEntityManagerFactory("Persistence");
em = emf.createEntityManager();
}
public void addNewEntry(){
Blogentry blogentry = new Blogentry();
blogentry.setTitle("Test");
blogentry.setContent("asdfasfas");
em.persist(blogentry);
}
}
所以我的托管bean调用了这个方法。直到这里没有问题。但由于没有调用初始化方法,我在 em.persist 中获得了NPE。
为什么没有调用initialize方法?我在Glassfish服务器上运行它。
问候。
答案 0 :(得分:21)
诸如@PostConstruct
之类的Java EE bean注释仅适用于容器管理的bean。如果您只是自己调用new BlogEntryDao
,则容器不会拦截创建并调用@PostConstruct
方法。
(此外,您最好使用@PersistenceContext
或@PersistenceUnit
,而不是在EntityManagerFactory
方法中手动提取initialize()
,您应该创建一个{每次调用EntityManager
时都会{1}},因为它们是短暂的。进行这些更改将根本不需要addNewEntry()
。)
答案 1 :(得分:13)
由于此问题首先在Google上出现“postconstruct not called”,因此除了使用@PostConstruct
关键字而不是将new
置于“@PostConstruct
”之外,可能无法调用addNewEntry()
方法的另一个原因Spring bean就是你有一个循环依赖。
如果这个bean依赖于另一个依赖于这个bean的bean,那么你的另一个bean可能会在初始化BlogEntryDao
之前调用@AutoWired
,即使BlogEntryDao是该另一个bean的依赖项。
这是因为Spring因为循环引用而不知道您想要首先加载哪个bean。在这种情况下,可以删除循环引用或使用@Value
/ {{1}}构造函数参数而不是成员值或setter,或者如果使用xml配置,也许您可以交换定义bean的顺序
答案 2 :(得分:11)
我的申请中遇到了同样的问题。 你没有发布你的bean上下文配置xml文件(所以我不确定它是否是同一个问题)但在我的情况下添加这一行:
<context:annotation-config/>
解决了我的问题。
您需要<context:annotation-config/>
或<context:component-scan/>
才能启用@PostConstruct注释。
答案 3 :(得分:2)
在我的情况下,没有调用@PostConstruct,因为我的initialize()方法是静态的,并且还抛出异常。无论哪种情况,该方法都被忽略。我希望它可以帮助那些犯同样错误的人。 这可以在控制台中找到:
WARNING: JSF1044: Method '<XXX>' marked with the 'javax.annotation.PostConstruct' annotation cannot be static. This method will be ignored.
WARNING: JSF1047: Method '<XXX>' marked with the 'javax.annotation.PostConstruct' annotation cannot declare any checked exceptions. This method will be ignored.
答案 4 :(得分:1)
在我的情况下,未调用@PostConstruct
方法,因为我直接在其他服务bean(即myService.myProperty)中引用了spring服务bean的public instance variable
。当我为属性(即getter method
)公开getMyProperty()
并使用它来获取属性时,再次调用@PostConstruct
方法。我也做了myProperty
private
,以防止将来发生任何意外的直接引用。
还请注意,如果您未在带有注释的@Bean
中向@Configuration
显式注册该类,而仅依靠@Autowired
,则@PostConstruct
方法可能不会在启动时立即执行。仅当自动连线类的方法之一被另一个类引用并调用时,该类才会被加载,并且仅在那时才调用@PostConstruct
方法。换句话说,仅通过使用@Autowired
就可以从根本上懒加载类。如果要在启动时加载它,请向@Bean
关于@Bean
和@Autowired
Difference between @Bean and @Autowired之间的区别,这里有一个很好的SO主题
编辑:最后一句话。当您有一个Web应用程序并决定用@RequestScope
注释您的类时,每次有新请求进入时,都会调用@Postconstruct
注释的方法。这是因为@RequestScope
指示spring创建每次有新请求进入时,该类中都会有一个新的instance
。如果希望所有请求都使用相同的实例,则可以如上所述使用@Bean
,但也可以使用注释{ {1}}高于您的班级。这将导致在启动时急切地加载该类。
答案 5 :(得分:0)
确保具有@Postconstruct
方法的类位于同一包中。我将类文件移到了主包中,并且可以正常工作。
答案 6 :(得分:0)
使用 Spring 时,请确保使用来自正确包的正确 PostConstruct 注释。
javax.annotation.PostConstruct
应该是那个。不是例如:
jakarta.annotation.PostConstruct
我花了一点时间才弄清楚为什么我的 PostConstruct 只有一个不起作用。
答案 7 :(得分:0)
就我而言,我在类路径中有两个 javax.annotation.PostConstruct
实例。一个与 war 包捆绑在一起,另一个由 tomcat 提供。当 Spring 扫描 @PostConstruct
注释时,它会比较这两个不同的实例。因此,在扫描时没有选择 @PostConstruct
注释的方法。
只提供一个 javax.annotation-api
库实例解决了这个问题。