为啥使用@PostConstruct?

Posted

技术标签:

【中文标题】为啥使用@PostConstruct?【英文标题】:Why use @PostConstruct?为什么使用@PostConstruct? 【发布时间】:2011-03-25 07:23:58 【问题描述】:

在托管 bean 中,@PostConstruct 在常规 Java 对象构造函数之后调用。

为什么我要使用@PostConstruct 来通过 bean 进行初始化,而不是使用常规的构造函数本身?

【问题讨论】:

我的印象是构造函数注入通常更适合允许依赖项为final。鉴于这种模式,为什么要将 @PostConstruct 添加到 J2EE - 他们肯定已经看到了另一个用例? @mjaggard 我的理解是@PostConstruct 不用于适当地注入您的依赖项,以确保它们是final 等;它被用作一个实用程序的注释,即使该对象由 IoC 容器多次构造,也应该只调用一次。并不是说我知道这将如何在容器中发生,但它显然会发生(请参阅接受的答案)。 【参考方案1】:

因为在调用构造函数时,bean 尚未初始化 - 即没有注入依赖项。在@PostConstruct 方法中,bean 已完全初始化,您可以使用依赖项。

因为这是保证此方法在 bean 生命周期中仅被调用一次的协定。容器在其内部工作中多次实例化 bean 可能会发生(尽管不太可能),但它保证 @PostConstruct 只会被调用一次。

【讨论】:

如果构造函数本身自动装配所有依赖项 - 那么 bean 也可以在构造函数中完全初始化(在手动设置所有自动装配字段之后)。 一个bean的构造函数可能被多次调用的情况是什么? 可能类似于“钝化”。如果容器决定将 bean 存储在磁盘存储上,然后从那里恢复它。 构造函数被多次调用的可能性不大。当容器实例化一个代理时,您会看到构造函数至少为代理调用一次,为真正的 bean 调用一次。 请注意,在服务器重新启动后立即加载页面时,调用 @PostConstruct 方法。 (这可能是一个 JBoss 错误。)【参考方案2】:

主要的问题是:

在构造函数中,依赖项的注入尚未发生*

*明显不包括构造函数注入


现实世界的例子:

public class Foo 

    @Inject
    Logger LOG;

    @PostConstruct
    public void fooInit()
        LOG.info("This will be printed; LOG has already been injected");
    

    public Foo() 
        LOG.info("This will NOT be printed, LOG is still null");
        // NullPointerException will be thrown here
    


重要提示@PostConstruct@PreDestroy 已经完全是 removed in Java 11

要继续使用它们,您需要将 javax.annotation-api JAR 添加到您的依赖项中。

Maven

<!-- https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api -->
<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.2</version>
</dependency>

分级

// https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api
compile group: 'javax.annotation', name: 'javax.annotation-api', version: '1.3.2'

【讨论】:

in a constructor, the injection of the dependencies has not yet occurred. 对于 setter 或字段注入为 true,但对于构​​造函数注入则不为 true。 在 Java 11 中删除了 @PostConstruct 后,我​​们现在如何使用 Java 11 处理这个现实世界的示例? @tet 如回答中所述,您需要使用 javax.annotation-api 库。这些注解在 Java 11 中已被删除,但自 Java 9 起已被标记为已弃用。 我仍然可以在java 11 中看到@PostConstruct【参考方案3】:

如果您的类在构造函数中执行所有初始化,那么@PostConstruct 确实是多余的。

但是,如果你的类有使用setter方法注入的依赖,那么类的构造函数就不能完全初始化对象,有时需要在调用完所有setter方法后进行一些初始化,因此@987654323的用例@。

【讨论】:

@staffman:我这边加一个。如果我希望使用从数据库中获取的值来初始化 inputtext 字段,我可以在 PostConstruct 的帮助下完成,但在构造函数中尝试执行相同操作时会失败。我有这个要求在不使用 PostContruct 的情况下进行初始化。如果你有时间,你能不能也回答一下:***.com/questions/27540573/…【参考方案4】:

每当涉及某种代理或远程处理时,基于构造函数的初始化也不会按预期工作。

每当一个 EJB 被反序列化,并且每当为其创建一个新代理时,都会调用 ct...

【讨论】:

以上是关于为啥使用@PostConstruct?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我在 JTA EJB 的 @PostConstruct 方法中收到 TransactionRequiredException?

多个类中 使用@PostConstruct,加载先后顺序

@PostConstruct

@PostConstruct方法的使用以及原理,@Component+@PostConstruct方法将一个方法完成初始化操作

@PostConstruct注解介绍

8 -- 深入使用Spring -- 2...4 使用@PostConstruct和@PreDestroy定制生命周期行为