Spring @PostConstruct与init-method属性


103

使用@PostConstruct注释和声明与init-methodSpring XML配置中相同的方法之间有什么区别吗?

Answers:


153

实际上,我认为没有什么区别,但是它们的工作方式有优先考虑的地方。@PostConstructinit-method是BeanPostProcessors。

  1. @PostConstruct是JSR-250注释,而init-methodSpring是具有初始化方法的方法。
  2. 如果有@PostConstruct方法,将在调用初始化方法之前先调用此方法。
  3. 如果你的bean实现的InitializingBean和覆盖afterPropertiesSet,首先@PostConstruct被调用,然后afterPropertiesSetinit-method

有关更多信息,您可以查看Spring的参考文档

在JSR 250规范之前,在xml中使用init-method是首选方式,因为它可以将Java类(bean)与任何特定于Spring的类/注释分离。因此,如果要构建不需要依赖Spring基础结构bean的库,那么在创建方法期间,您可以指定需要称为初始化方法的方法。

现在,随着Java EE中的JSR 250规范的引入以及这些注释的Spring支持,对Spring框架的依赖性已在一定程度上降低了。

但是我必须承认,添加这些东西可以提高代码的可读性,因此两种方法都有其优缺点。


23
如果bean使用的是以上方法中的一种以上并依赖于初始化的顺序,那么它将变得非常复杂且难以维护。
Donal Fellows

2
@Donal非常正确。只是提供有关其工作方式的信息。
Aravind A

1
有一个重要的区别:您需要专门配置Spring以处理注释以使@PostConstruct起作用:stackoverflow.com/q/3434377/134898
Juan Calero 2014年

@DonalFellows,但如果您打算参加认证考试,则需要知道这一点;)
S.Klechkovski

@DonalFellows-您能否详细说明您的答案?我的意思是,如果bean依赖于初始化顺序,则会遇到困难。其实我想知道哪个更好。PostConstruct或Bean(initMethod =“ init”)在服务任何请求之前从Bean做一些初始化工作?
Ayaskant

19

没有真正的区别。这取决于您偏好配置系统的方式,这是个人选择的问题。我自己,我更喜欢@PostConstruct为自己的代码使用注释(因为只有在调用该方法之后才正确配置Bean),并且我init-method在从非Spring感知的库中实例化Bean时使用(当然不能在此处应用注释!)但是我完全可以理解人们想要以一种或另一种方式来做到这一点。



3

正如您在Bean创建生命周期回调的下图中所看到的。

Bean创建生命周期回调

这3个步骤发生在Bean创建生命周期回调中:

  1. 提到@PostConstruct将被称为。
  2. 如果InitializingBean执行,afterPropertiesSet()则将被调用。
  3. 如果bean定义包含init-method或,@Bean(initmethod="..")则它将调用init方法。

该图来自Pro Spring 5:Spring框架及其工具的深入指南


3

可能是差异之间@PostConstructinit-method因为 @PostConstruct在被处理postProcessAfterInitialization豆初始化(相AbstractAutowireCapableBeanFactory.initializeBean()法)的CommonAnnotationBeanPostProcessor,而init方法被完成后调用postProcessBeforeInitialization(开始之前,并且对于这件事情,相postProcessAfterInitialization相)。
编辑:因此,顺序是:1)postProcessBeforeInitialization阶段,2)init方法被调用,3)postProcessAfterInitialization阶段,调用@PostConstruct方法

(附带说明,已接受答案的声明

@PostConstruct,初始化方法是BeanPostProcessors

是不是很正确:@PostConstruct通过处理BeanPostProcessorinit方法是不是)。

差一些,如果(潜在的自定义)BeanPostProcessor,其配置有(Ordered.getOrder())后执行CommonAnnotationBeanPostProcessor,是做一些在其严重的postProcessBeforeInitialization方法。
没有用默认的Spring配置任何区别BeanPostProcessors,因为所有的BeanPostProcessors这些配置后要执行CommonAnnotationBeanPostProcessor,不执行任何操作postProcessBeforeInitialization方法。

总而言之,在99%的案例中,可接受的答案和类似的答案都是正确的……并且,该帖子旨在向“细节中的魔鬼”致敬


嗨!这令人困惑,如果PostConstruct在init-method之前运行,如果init方法在postProcessBeforeInitialization之后和postProcessAfterInitialization之前运行,那么postProcessAfterInitialization会如何处理呢?
Maxrunner,

@Maxrunner,很抱歉给您带来的混乱,非常感谢您告诉我们!实际上,我从来没有说过PostConstruct在初始化方法之前运行。无论如何,我做了一些澄清以更新我的答案
igor.zh '19

2

完整代码在这里:https : //github.com/wkaczurba/so8519187spring-boot

使用注释:

@Slf4j
@Component
public class MyComponent implements InitializingBean {

    @Value("${mycomponent.value:Magic}")
    public String value;

    public MyComponent() {
        log.info("MyComponent in constructor: [{}]", value); // (0) displays: Null
    }

    @PostConstruct
    public void postConstruct() {
        log.info("MyComponent in postConstruct: [{}]", value); // (1) displays: Magic
    }

    @Override // init-method; overrides InitializingBean.afterPropertiesSet()
    public void afterPropertiesSet() {
        log.info("MyComponent in afterPropertiesSet: [{}]", value);  // (2) displays: Magic
    }   

    @PreDestroy
    public void preDestroy() {
        log.info("MyComponent in preDestroy: [{}]", value); // (3) displays: Magic
    }
}

获取我们:

刷新org.springframework.context ...

构造函数中的MyComponent:[null]
postConstruct中的MyComponent:[Magic]
afterPropertiesSet中的MyComponent:[Magic]
...

在启动时注册JMX暴露的
bean在0.561秒内启动了DemoApplication(JVM运行1.011)
关闭org.springframework.context。 。关闭时注销JMX暴露的bean

...
preDestroy中的MyComponent:[Magic]

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.