Java面试题:@PostConstruct、init-method和afterPropertiesSet执行顺序? ...

打印 上一主题 下一主题

主题 894|帖子 894|积分 2682

在Spring框架中,@PostConstruct注解、init-method属性、以及afterPropertiesSet()方法通常用于初始化Bean的逻辑。它们都提供了在Bean创建和初始化完成后执行的方法,但执行顺序有所不同。
想要知道@PostConstruct、init-method、afterPropertiesSet()的执行顺序,只要搞明白它们各安闲什么时候被谁调用就行了。
代码如下:
  1. import org.springframework.beans.factory.InitializingBean;
  2. import javax.annotation.PostConstruct;
  3. public class Foo implements InitializingBean {
  4.     public void init(){
  5.         System.out.println("执行了init生命周期的初始化回调");
  6.     }
  7.     @PostConstruct
  8.     public void postConstruct(){
  9.         System.out.println("执行了postConstruct生命周期的初始化回调");
  10.     }
  11.     @Override
  12.     public void afterPropertiesSet() {
  13.         System.out.println("执行了afterPropertiesSet生命周期的初始化回调");
  14.     }
  15. }
复制代码
  1. import org.springframework.context.annotation.Bean;
  2. import org.springframework.context.annotation.Configuration;
  3. @Configuration
  4. public class InitConfiguration {
  5.     @Bean(initMethod = "init")
  6.     public Foo getInitMethodBean() {
  7.         return new Foo();
  8.     }
  9. }
复制代码
执行启动类,可以看到在控制台中输出:
  1. 执行了postConstruct生命周期的初始化回调
  2. 执行了afterPropertiesSet生命周期的初始化回调
  3. 执行了init生命周期的初始化回调
复制代码
@PostConstruct是Java EE 5引入的一个注解,它用于标记一个方法,该方法会在依赖注入完成后自动执行。这意味着,一旦Spring容器完成了Bean的实例化和属性赋值,就会调用这个方法。通常,我们会在这个方法中做一些初始化工作,比如启动服务、初始化数据库连接等。
init-method属性是Spring Bean的一个属性,它允许我们指定一个初始化方法。这个方法会在Bean实例化并完成属性注入后自动执行。与@PostConstruct注解不同的是,init-method属性并不依赖于Spring容器,因此可以在没有Spring的情况中运行。
afterPropertiesSet是SpringFramework中的一个初始化方法,它属于 InitializingBean接口的一部分。当bean的全部属性被Spring容器设置之后,这个方法会被自动调用。它允许开发者在bean属性设置完成之后执行一些特定的操作,如数据库连接池的初始化等。这个方法是在执行其他初始化方法之前被调用的。
源码分析:
通过断点调试发现几个初始化方法都定位到AbstractAutowireCapableBeanFactory的initializeBean方法中
  1. protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
  2.     if (System.getSecurityManager() != null) {
  3.       AccessController.doPrivileged(new PrivilegedAction<Object>() {
  4.         @Override
  5.         public Object run() {
  6.           invokeAwareMethods(beanName, bean);
  7.           return null;
  8.         }
  9.       }, getAccessControlContext());
  10.     }
  11.     else {
  12.       invokeAwareMethods(beanName, bean);
  13.     }
  14.     Object wrappedBean = bean;
  15.     if (mbd == null || !mbd.isSynthetic()) {
  16.       // 此处执行的是@PostConstruct注解的方法 InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization
  17.       wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  18.     }
  19.     try {
  20.       // 执行的是afterPropertiesSet和init-method方法      
  21.       invokeInitMethods(beanName, wrappedBean, mbd);
  22.     }
  23.     catch (Throwable ex) {
  24.       throw new BeanCreationException(
  25.           (mbd != null ? mbd.getResourceDescription() : null),
  26.           beanName, "Invocation of init method failed", ex);
  27.     }
  28.     if (mbd == null || !mbd.isSynthetic()) {
  29.       wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  30.     }
  31.     return wrappedBean;
  32.   }
复制代码
执行afterPropertiesSet和init-method方法,在invokeInitMethods方法里面,如下:
  1. protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
  2.       throws Throwable {
  3.     boolean isInitializingBean = (bean instanceof InitializingBean);
  4.     if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
  5.       if (logger.isDebugEnabled()) {
  6.         logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
  7.       }
  8.       if (System.getSecurityManager() != null) {
  9.         try {
  10.           AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
  11.             @Override
  12.             public Object run() throws Exception {
  13.               ((InitializingBean) bean).afterPropertiesSet();
  14.               return null;
  15.             }
  16.           }, getAccessControlContext());
  17.         }
  18.         catch (PrivilegedActionException pae) {
  19.           throw pae.getException();
  20.         }
  21.       }
  22.       else {
  23.         // 执行afterPropertiesSet方法
  24.         ((InitializingBean) bean).afterPropertiesSet();
  25.       }
  26.     }
  27.     if (mbd != null) {
  28.       String initMethodName = mbd.getInitMethodName();
  29.       if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
  30.           !mbd.isExternallyManagedInitMethod(initMethodName)) {
  31.         // 执行自定义的init-method方法
  32.         invokeCustomInitMethod(beanName, bean, mbd);
  33.       }
  34.     }
  35.   }
复制代码
 
最终的结论是:@PostConstruct > afterPropertiesSet() > initMethod()的顺序
 
往期面试题:
Java面试题:SimpleDateFormat是线程安全的吗?使用时应该注意什么?
Java面试题:细数ThreadLocal大坑,内存泄漏本可避免
Java面试题:请谈谈对ThreadLocal的理解?
Java面试题:为什么HashMap不建议使用对象作为Key?
Java面试题:你知道Spring的IOC吗?那么,它为什么这么重要呢?
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

民工心事

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表