为什么没有调用PostConstruct?

时间:2013-08-10 12:04:36

标签: java java-ee ejb

我正在开发一个简单的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服务器上运行它。

问候。

8 个答案:

答案 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 库实例解决了这个问题。