31

我正在开发一个简单的 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 。

为什么没有调用初始化方法?我在 Glassfish 服务器上运行它。

问候。

4

9 回答 9

24

Java EE bean 注释等@PostConstruct仅适用于容器管理的 bean。如果您只是简单地调用new BlogEntryDao自己,则容器不会拦截创建并调用@PostConstruct方法。

(此外,您最好使用@PersistenceContext@PersistenceUnit代替手动获取方法EntityManagerFactory中的initialize(),并且您应该EntityManager为每次调用创建一个addNewEntry(),因为它们是短暂的。进行这些更改将完全initialize()消除)

于 2013-08-10T12:18:42.427 回答
19

我在我的应用程序中遇到了同样的问题。您没有发布您的 bean 上下文配置 xml 文件(所以我不确定它是否是同一个问题)但在我的情况下添加此行:

<context:annotation-config/>

解决了我的问题。您需要<context:annotation-config/><context:component-scan/>启用 @PostConstruct 注释。

于 2015-10-30T17:08:22.150 回答
18

由于这个问题首先出现在 Google 上,用于“未调用 postconstruct”,因此除了使用关键字而不是放入Spring bean@PostConstruct之外,可能不会调用方法的另一个原因是,如果您有循环依赖项。 new@PostConstruct

如果这个 bean 依赖于另一个依赖于这个 bean 的 bean,那么您的另一个 bean 可能会在初始化addNewEntry()之前调用BlogEntryDao,即使 BlogEntryDao 是另一个 bean 的依赖项。

这是因为由于循环引用,Spring 不知道您要首先加载哪个 bean。在这种情况下,可以删除循环引用或使用@AutoWired/@Value构造函数参数而不是成员值或设置器,或者如果使用 xml 配置,也许您可​​以交换定义 bean 的顺序。

于 2014-12-09T02:46:47.087 回答
5

在我的情况下,@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.
于 2016-12-12T16:49:59.250 回答
1

在我的情况下@PostConstruct,方法没有被调用,因为我直接在其他服务 bean 中引用public instance variable了 spring 服务 bean(即 myService.myProperty)。当我公开getter method该属性(即getMyProperty())并使用它来获取该属性时,@PostConstruct再次调用了该方法。我还做了myProperty private以防止将来发生任何意外的直接引用。

另请注意,如果您没有@Bean在带@Configuration注释的类中显式注册该类,而是单独依赖该类@Autowired,则该@PostConstruct方法可能不会在启动时立即执行。只有当自动装配类的其中一个方法被另一个类引用和调用时,才会加载该类,并且只有在那个时候才会@PostConstruct调用该方法。换句话说,只使用@Autowired你本质上是延迟加载一个类。如果要在启动时加载它,请使用@Bean

这是一个关于@Bean 和 @Autowired 之间@Bean的区别和区别的很好的 SO 线程@Autowired

编辑:最后一句话。当你有一个 web 应用程序并决定用注释你的类时,@RequestScope每次@Postconstruct有新请求进来时都会调用注释方法。这是因为每次有新请求进来时都会@RequestScope指示 spring 创建一个新instance的类。如果你希望所有请求都使用相同的实例,那么您可以@Bean如上所述使用,但您也可以使用@Singleton类上方的注释。这将导致类在启动时被急切地加载。

于 2020-08-13T14:53:45.160 回答
1

使用 Spring 时,请确保您使用来自正确包的正确 PostConstruct 注释。

javax.annotation.PostConstruct

应该是那个。不是例如:

jakarta.annotation.PostConstruct

我花了一点时间才弄清楚为什么我的 PostConstruct 中只有一个不起作用。

于 2021-02-06T15:22:14.963 回答
0

就我而言,我有两个javax.annotation.PostConstruct内部类路径实例。一个与war包捆绑在一起,另一个由tomcat提供。当 Spring 扫描@PostConstruct注解时,它会比较这两个不同的实例。因此,@PostConstruct在扫描时未选择带注释的方法。

只提供一个库实例javax.annotation-api解决了这个问题。

于 2021-02-11T18:31:32.750 回答
0

确保具有@Postconstruct方法的类位于同一个包中。我将类文件移动到主包并且它工作。

于 2020-11-16T04:01:36.510 回答
0

由于已经提到了大多数方法。但是,也可以在类的配置文件中创建一个 bean

org.springframework.context.annotation.CommonAnnotationBeanPostProcessor

;

这将启用PostConstructPreDestroy注释。

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"></bean>

同样对于Predestroy需要调用context.registerShutDownHook()

于 2021-08-27T21:29:36.100 回答