繁体   English   中英

为什么不调用 PostConstruct?

[英]Why is PostConstruct not called?

我正在开发一个简单的 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 调用了这个方法。 直到这里没有问题。 但是由于没有调用 initialize 方法,我在em.persist 中得到了一个 NPE。

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

问候。

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

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

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

<context:annotation-config/>

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

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

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

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

在我的例子中,@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.

在我的例子中,@ @PostConstruct方法没有被调用,因为我直接在其他服务 bean(即 myService.myProperty)中引用了 spring 服务 bean 的public instance variable 当我为属性创建一个公共getter method (即getMyProperty() )并使用它来获取属性时,@ @PostConstruct方法再次被调用。 此外,我将myProperty设为private以防止将来发生任何意外的直接引用。

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

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

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

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

javax.annotation.PostConstruct

应该是那个。 不是例如:

jakarta.annotation.PostConstruct

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

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

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

仅提供javax.annotation-api库的一个实例解决了该问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM