@PostConstruct、afterPropertiesSet和init-method的执行顺序

  • Post author:
  • Post category:其他




@PostConstruct、init-method、afterPropertiesSet() 的执行顺序

想要知道

@PostConstruct



init-method



afterPropertiesSet()

的执行顺序,只要搞明白它们各自在什么时候被谁调用就行了。

程序版本:Spring Boot 2.3.5.RELEASE

准备好要验证的材料:

public class Foo implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet()");
    }

    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct");
    }

    private void initMethod() {
        System.out.println("initMethod()");
    }
}
@Configuration
public class FooConfiguration {
    @Bean(initMethod = "initMethod")
    public Foo foo() {
        return new Foo();
    }
}

执行启动类,可以看到在控制台中输出:

@PostConstruct

afterPropertiesSet()

initMethod()

说明执行顺序是:@PostConstruct、afterPropertiesSet()、init-method

接下来将跟着源码来了解为什么是这个顺序。




@PostConstruct

标注的方法在何时被谁调用

首先,在

init()

中打个断点,然后以 debug 的方式启动项目,得到下面的调用栈:

init:23, Foo (com.xurk.init.foo)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:389, InitDestroyAnnotationBeanPostProcessor$LifecycleElement (org.springframework.beans.factory.annotation)
invokeInitMethods:333, InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata (org.springframework.beans.factory.annotation)
postProcessBeforeInitialization:157, InitDestroyAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation)
applyBeanPostProcessorsBeforeInitialization:415, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
initializeBean:1786, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
doCreateBean:594, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:516, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
lambda$doGetBean$0:324, AbstractBeanFactory (org.springframework.beans.factory.support)
getObject:-1, 2103763750 (org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$169)
getSingleton:234, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
doGetBean:322, AbstractBeanFactory (org.springframework.beans.factory.support)
getBean:202, AbstractBeanFactory (org.springframework.beans.factory.support)
preInstantiateSingletons:897, DefaultListableBeanFactory (org.springframework.beans.factory.support)
finishBeanFactoryInitialization:879, AbstractApplicationContext (org.springframework.context.support)
refresh:551, AbstractApplicationContext (org.springframework.context.support)
refresh:143, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
refresh:758, SpringApplication (org.springframework.boot)
refresh:750, SpringApplication (org.springframework.boot)
refreshContext:405, SpringApplication (org.springframework.boot)
run:315, SpringApplication (org.springframework.boot)
run:1237, SpringApplication (org.springframework.boot)
run:1226, SpringApplication (org.springframework.boot)
main:14, InitApplication (com.xurk.init)

从上往下看,跳过使用 sun.reflect 的方法,进入到第6行。

public void invoke(Object target) throws Throwable {
   ReflectionUtils.makeAccessible(this.method);
   this.method.invoke(target, (Object[]) null);
}

很明显,这里是在通过反射调用某个对象的一个方法,并且这个“某个对象”就是我们定义的

Foo

的实例对象了。


那么这里的 method 又是在什么时候进行赋值的呢?


invoke(...)

全路径是: org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.LifecycleElement#invoke

并且

LifecycleElement

有且只有一个显示声明并且带参数的构造器,这个要传入构造器的参数正是

invoke(...)

使用的那个

Method

对象。

接下来就是查一下,是谁在

new LifecycleElement

于是定位到:org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#buildLifecycleMetadata

private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
    if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
        return this.emptyLifecycleMetadata;
    }

    List<LifecycleElement> initMethods = new ArrayList<>();
    List<LifecycleElement> destroyMethods = new ArrayList<>();
    Class<?> targetClass = clazz;

    do {
        final List<LifecycleElement> currInitMethods = new ArrayList<>();
        final List<LifecycleElement> currDestroyMethods = new ArrayList<>();

        ReflectionUtils.doWithLocalMethods(targetClass, method -> {
            if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
                LifecycleElement element = new LifecycleElement(method);
                currInitMethods.add(element);
                if (logger.isTraceEnabled()) {
                    logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
                }
            }
            if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
                currDestroyMethods.add(new LifecycleElement(method));
                if (logger.isTraceEnabled()) {
                    logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
                }
            }
        });

        initMethods.addAll(0, currInitMethods);
        destroyMethods.addAll(currDestroyMethods);
        targetClass = targetClass.getSuperclass();
    }
    while (targetClass != null && targetClass != Object.class);

    return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
            new LifecycleMetadata(clazz, initMethods, destroyMethods));
}

第15-26行是在通过反射判断方法上是否存在某个注解,如果是的话就加到一个集合中,在最后用于构建

LifecycleMetadata

实例。

**那么15行的

this.initAnnotationType

是不是就是我们要找的

@PostConstruct

注解呢?**继续找

initAnnotationType

字段被赋值了什么内容。

在这里因为我们要查找的是被赋值的内容,所以在使用IDE进行查找时只要关注 write 相关的内容就行了。

在这里插入图片描述

到这里,已经知道了是在

CommonAnnotationBeanPostProcessor

的构造器中进行 set 的,也就是当创建

CommonAnnotationBeanPostProcessor

实例的时候就会进行赋值,并且

CommonAnnotationBeanPostProcessor



InitDestroyAnnotationBeanPostProcessor

的子类。

在这里插入图片描述

并且,

CommonAnnotationBeanPostProcessor

构造器中调用的

setInitAnnotationType

其实是它父类的方法,实际是对

InitDestroyAnnotationBeanPostProcessor

的实例的

initAnnotationType

字段进行赋值。

到这里已经可以明确

buildLifecycleMetadata(...)

中判断的正是

@PostConstruct

再回到

buildLifecycleMetadata(...)

,查看其使用的

doWithLocalMethods(...)

的实现。

public static void doWithLocalMethods(Class<?> clazz, MethodCallback mc) {
    Method[] methods = getDeclaredMethods(clazz, false);
    for (Method method : methods) {
        try {
            mc.doWith(method);
        }
        catch (IllegalAccessException ex) {
            throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
        }
    }
}

很简单,通过反射获得类的所有方法,然后调用一个函数接口的方法,这个函数接口的实现就是判断方法是不是被

@PostConstruct

标注,如果被标注的话放到一个名字叫

currInitMethods

的集合中。

看到这里或许你已经意识到了,

@PostConstruct


可以标注多个方法

,并且因为反射获取方法时是根据声明顺序的、

currInitMethods



ArrayList

,两者之间的顺序是一样的。

好了,被

@PostConstruct

标注的方法已经找到放到集合中了,将被用来构建

LifecycleMetadata

实例了。


buildLifecycleMetadata(...)

方法返回一个

LifecycleMetadata

实例,这个返回值中包含传入Class实例中得到的所有被

@PostConstruct

标注的 Method 实例,

接下来要看看是谁在调用

buildLifecycleMetadata(...)

方法,看看它是怎么用的?

追溯到

findLifecycleMetadata(...)



findLifecycleMetadata(...)

又有好几处被调用。

在这里插入图片描述

查看最早得到的方法调用栈,

查到

postProcessBeforeInitializatio(...)

,它又是再被谁调用?

init:23, Foo (com.xurk.init.foo)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:389, InitDestroyAnnotationBeanPostProcessor$LifecycleElement (org.springframework.beans.factory.annotation)
invokeInitMethods:333, InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata (org.springframework.beans.factory.annotation)
postProcessBeforeInitialization:157, InitDestroyAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation)
applyBeanPostProcessorsBeforeInitialization:415, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
initializeBean:1786, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)

跟着方法调用栈,我们来到 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
      throws BeansException {

   Object result = existingBean;
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
      Object current = processor.postProcessBeforeInitialization(result, beanName);
      if (current == null) {
         return result;
      }
      result = current;
   }
   return result;
}

在这个方法,遍历 BeanPostProcessors 集合并执行每个 BeanPostProcessor 的

postProcessBeforeInitialization(...)

方法。

**那么

getBeanPostProcessors()

中的内容又是在什么时候放进去的呢?都有哪些内容?**可以通过

AnnotationConfigUtils



CommonAnnotationBeanPostProcessor

查找,这里就不再赘述了。

查找

applyBeanPostProcessorsBeforeInitialization(...)

的调用者,来到org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
   if (System.getSecurityManager() != null) {
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
         invokeAwareMethods(beanName, bean);
         return null;
      }, getAccessControlContext());
   }
   else {
      invokeAwareMethods(beanName, bean);
   }

   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }

   try {
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }
   if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }

   return wrappedBean;
}

顾名思义,在这个方法中对 Bean 进行初始化。是在被注入前一定要经过的过程,到这里被

@PostConstruct

标注的方法执行已经完成了。至于这个方法谁调用可以自己查看调用栈。




init-method、afterPropertiesSet()

的调用

细心的朋友可能已经发现了在

initializeBean(...)

中有调用到一个叫做

invokeInitMethods(...)

的方法。

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
      throws Throwable {

   boolean isInitializingBean = (bean instanceof InitializingBean);
   if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
      if (logger.isTraceEnabled()) {
         logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
      }
      if (System.getSecurityManager() != null) {
         try {
            AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
               ((InitializingBean) bean).afterPropertiesSet();
               return null;
            }, getAccessControlContext());
         }
         catch (PrivilegedActionException pae) {
            throw pae.getException();
         }
      }
      else {
         ((InitializingBean) bean).afterPropertiesSet();
      }
   }

   if (mbd != null && bean.getClass() != NullBean.class) {
      String initMethodName = mbd.getInitMethodName();
      if (StringUtils.hasLength(initMethodName) &&
            !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
            !mbd.isExternallyManagedInitMethod(initMethodName)) {
         invokeCustomInitMethod(beanName, bean, mbd);
      }
   }
}

BeanDefinition是Bean定义的一个抽象。类似于在Java中存在Class类用于描述一个类,里面有你定义的 Bean 的各种信息。

在第4行,判断是不是

InitializingBean

,如果是的话会进行类型强转,然后调用

afterPropertiesSet()

在第26行,获得到自定义初始化方法的名字,然后在第30行调用

invokeCustomInitMethod

执行完成。



顺序的确定

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
   if (System.getSecurityManager() != null) {
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
         invokeAwareMethods(beanName, bean);
         return null;
      }, getAccessControlContext());
   }
   else {
      invokeAwareMethods(beanName, bean);
   }

   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }

   try {
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }
   if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }

   return wrappedBean;
}


initializeBean(...)

方法中,先执行

applyBeanPostProcessorsBeforeInitialization(...)

在执行

invokeInitMethods(...)



applyBeanPostProcessorsBeforeInitialization(...)

会执行被

@PostConstruct

标注的方法,

invokeInitMethods(...)

会执行

afterPropertiesSet()

和自定义的初始化方法,并且

afterPropertiesSet()

在自定义的初始化方法之前执行,所以它们之间的执行顺序是:

@PostConstruct > afterPropertiesSet() > initMethod()



版权声明:本文为xurk0922原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。