Source code analysis Spring container starts and destroys resources


       When the spring project starts, some pre- and post-processing can be added in the life cycle of the bean, and it can also be used for resource initialization and resource destruction. This article combines the source code to analyze some of the extended functions and execution order of spring. First look at the bean initialization flowchart, and then the execution sequence will be described in detail later.
insert image description here

一、InitializingBean

       InitializingBean is an interface, the class implements this interface, rewrites the afterPropertiesSet method, and can perform some processing after bean instantiation and property assignment (populateBean method).

1. Source code

public interface InitializingBean {
    
    
    void afterPropertiesSet() throws Exception;
}

       Contains only one afterPropertiesSet method, and subclasses need to implement this method if they implement the interface.

2. spring boot source code call

(1) location

       The source code call location for processing this interface is as follows:

run() -> 
this.refreshContext(context) -> 
this.refresh(context) -> 
applicationContext.refresh() -> 
this.finishBeanFactoryInitialization(beanFactory) -> 
beanFactory.preInstantiateSingletons() -> DefaultListableBeanFactory.preInstantiateSingletons() -> 
this.getBean(beanName) -> 
this.doGetBean() -> 
this.createBean(beanName, mbd, args) -> 
AbstractAutowireCapableBeanFactory.createBean() -> 
this.doCreateBean(beanName, mbdToUse, args) -> 
this.initializeBean(beanName, exposedObject, mbd) -> 
this.invokeInitMethods(beanName, wrappedBean, mbd) -> ((InitializingBean)bean).afterPropertiesSet()

(2) call

       When the bean is initialized, the invokeInitMethods initialization method is executed. This method handles the afterPropertiesSet method of the InitializingBean interface and user-defined initialization methods. The user-defined method refers to the method specified by the initMethod attribute when declaring a bean by annotating @Bean. In addition to @Bean and @Component, @Component can only configure the name of the bean, which can be directly on the class Use, the spring container will load it as a bean; @Bean needs to be placed in the configuration class (@Configuration decoration), and spring cannot scan it in the base class.

       @Component source code:

@Target({
    
    ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
    
    
    String value() default "";
}

       Use @Bean to configure custom initialization methods:

@Configuration
public class BeanConfig {
    
    
    
    @Scope(value="singleton")
    @Bean(initMethod = "intMethod")
    public BeanDemo beanDemo(){
    
    
        return new BeanDemo("张三",18);
    }
}

       A class not only implements the InitializingBean interface, but also configures a custom initMethod method. Its execution order is: first the method of the InitializingBean interface-"initMethod method , as can be seen from the source code of the invokeInitMethods method:

  protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
    
    
        //bean对象实现了InitializingBean接口
        boolean isInitializingBean = bean instanceof InitializingBean;
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
    
    
            if (this.logger.isTraceEnabled()) {
    
    
                this.logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }

            if (System.getSecurityManager() != null) {
    
    
                try {
    
    
                    AccessController.doPrivileged(() -> {
    
    
                        ((InitializingBean)bean).afterPropertiesSet();
                        return null;
                    }, this.getAccessControlContext());
                } catch (PrivilegedActionException var6) {
    
    
                    throw var6.getException();
                }
            } else {
    
    
                //先执行InitializingBean接口的afterPropertiesSet方法
                ((InitializingBean)bean).afterPropertiesSet();
            }
        }

        if (mbd != null && bean.getClass() != NullBean.class) {
    
    
            //获取bean自定义的初始化方法
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) && (!isInitializingBean || !"afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) {
    
    
                //使用反射执行自定义方法methodToInvoke.invoke(bean)
                this.invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }

3. Usage scenarios

       It is used in the xxl-job project, through the afterPropertiesSet method to initialize the timing daemon thread, create a thread pool, etc. Look at some of the source code:

@Component
public class XxlJobAdminConfig implements InitializingBean, DisposableBean {
    
    

    private static XxlJobAdminConfig adminConfig = null;
    public static XxlJobAdminConfig getAdminConfig() {
    
    
        return adminConfig;
    }

    // ---------------------- XxlJobScheduler ----------------------

    private XxlJobScheduler xxlJobScheduler;

    //实现了InitializingBean接口,在Bean初始化完并把参数注入成功后会调用afterPropertiesSet()
    @Override
    public void afterPropertiesSet() throws Exception {
    
    
        adminConfig = this;

        xxlJobScheduler = new XxlJobScheduler();
        //初始化调度中心资源
        xxlJobScheduler.init();
    }

二、SmartInitializingSingleton

       SmartInitializingSingleton is an interface. The class implements this interface. Post-processing can be performed after the bean is instantiated and initialized. The execution of the method is triggered only when the bean is a singleton and not lazy-loaded. Specify the bean by annotating @Scope Whether it is a singleton or a multi-instance, the value is singleton: singleton (there is only one instance globally), the value is prototype: multi-instance (every time a bean is obtained is a new instance), the bean declared using @Bean or @Component defaults is a singleton.

1. Source code

public interface SmartInitializingSingleton {
    
    
    void afterSingletonsInstantiated();
}

       There is only one afterSingletonsInstantiated method, and subclasses can implement this method to initialize resources.

2. spring boot source code call

(1) location

       The source code call location for processing this interface is as follows:

run() -> 
this.refreshContext(context) -> 
this.refresh(context) -> 
applicationContext.refresh() -> 
this.finishBeanFactoryInitialization(beanFactory) -> 
beanFactory.preInstantiateSingletons() -> DefaultListableBeanFactory.preInstantiateSingletons() -> 
smartSingleton.afterSingletonsInstantiated()

(2) call

       SmartInitializingSingleton will be processed only after the bean has been instantiated, initialized, and the initial method is executed. Use while (true) to process the bean, first instantiate and initialize the bean through getBean, save it in the cache, and finally take the bean out of the cache. Process the bean whose type is SmartInitializingSingleton, and call its afterSingletonsInstantiated method, so this method is the last method executed for bean initialization. Look at the source code processing:

  do {
    
    
                while(true) {
    
    
                    RootBeanDefinition bd;
                    do {
    
    
                        do {
    
    
                            do {
    
    
                                if (!var2.hasNext()) {
    
    
                                    var2 = beanNames.iterator();

                                    while(var2.hasNext()) {
    
    
                                        beanName = (String)var2.next();
                                        //从缓存中获取bean
                                        Object singletonInstance = this.getSingleton(beanName);
                                        if (singletonInstance instanceof SmartInitializingSingleton) {
    
    
                                            StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize").tag("beanName", beanName);
                                            SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance;
                                            if (System.getSecurityManager() != null) {
    
    
                                                AccessController.doPrivileged(() -> {
    
    
                                                    smartSingleton.afterSingletonsInstantiated();
                                                    return null;
                                                }, this.getAccessControlContext());
                                            } else {
    
    
                                                                            smartSingleton.afterSingletonsInstantiated();//执行afterSingletonsInstantiated方法
                                            }

                                            smartInitialize.end();
                                        }
                                    }

                                    return;
                                }

                                beanName = (String)var2.next();
                                bd = this.getMergedLocalBeanDefinition(beanName);
                            } while(bd.isAbstract());
                        } while(!bd.isSingleton());
                    } while(bd.isLazyInit());

                    if (this.isFactoryBean(beanName)) {
    
    
                        bean = this.getBean("&" + beanName);
                        break;
                    }
                    //获取bean,会创建bean对象,并保存到缓存中
                    this.getBean(beanName);
                }
            } while(!(bean instanceof FactoryBean));

3. Usage scenarios

       It is used in the xxl-job project. When the bean has been initialized, the method modified by @XxlJob in the bean is added to the map collection, and the netty server and thread pool are initialized. Look at some of the source code:

public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationContextAware, SmartInitializingSingleton, DisposableBean {
    
    

    // 实现了SmartInitializingSingleton接口(只适用于单列bean),在bean实例初始化完成后,会调用afterSingletonsInstantiated方法
    @Override
    public void afterSingletonsInstantiated() {
    
    

        //初始化任务方法,处理所有Bean中使用@XxlJob注解标识的方法
        initJobHandlerMethodRepository(applicationContext);

        // refresh GlueFactory
        //重新设置GlueFactory的类型为SpringGlueFactory
        GlueFactory.refreshInstance(1);

        // super start
        try {
    
    
            //调用到XxlJobExecutor类的start方法,对一些资源进行初始化
            super.start();
        } catch (Exception e) {
    
    
            throw new RuntimeException(e);
        }
    }
}

三、@PostConstruct

       @PostConstruct is an annotation of jdk, which is also used to initialize resource usage. Spring uses InitDestroyAnnotationBeanPostProcessor to wrap @PostConstruct and @PreDestroy annotations, so that BeanPostProcessor can be used to call methods decorated with @PostConstruct and @PreDestroy.

1. Source code

@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
    
    
}

2. spring boot source code call

(1) location

       First look at the source code of the InitDestroyAnnotationBeanPostProcessor class:

public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {
    
    
    @Nullable
    private Class<? extends Annotation> initAnnotationType;
    @Nullable
    private Class<? extends Annotation> destroyAnnotationType;

    public InitDestroyAnnotationBeanPostProcessor() {
    
    
    }

    public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
    
    
        this.initAnnotationType = initAnnotationType;
    }

    public void setDestroyAnnotationType(Class<? extends Annotation> destroyAnnotationType) {
    
    
        this.destroyAnnotationType = destroyAnnotationType;
    }
}

       The InitDestroyAnnotationBeanPostProcessor class implements the MergedBeanDefinitionPostProcessor interface, which contains two properties of type Annotation. Annotation is the parent class of all annotations, that is, the parent class of @PostConstruct. initAnnotationType is used to identify the type of receiving initialization annotations, and destroyAnnotationType is used to identify the type of receiving and destroying annotations , which annotation to receive is implemented by the subclass CommonAnnotationBeanPostProcessor of InitDestroyAnnotationBeanPostProcessor.

       Look at some source code of CommonAnnotationBeanPostProcessor:

public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
    
    

    public CommonAnnotationBeanPostProcessor() {
    
    
        this.setInitAnnotationType(PostConstruct.class);
        this.setDestroyAnnotationType(PreDestroy.class);
    }
}

        The default constructor of the CommonAnnotationBeanPostProcessor class sets the type of initAnnotationType to PostConstruct and the type of destroyAnnotationType to PreDestroy.

       When registering BeanPostProcessor, a CommonAnnotationBeanPostProcessor will be added to the beanPostProcessors list collection, so that when the beanPostProcessors collection is traversed later to execute the postProcessBeforeInitialization method, the postProcessBeforeInitialization method of the InitDestroyAnnotationBeanPostProcessor class will be called. This method is modified by @PostConstruct through reflection execution method.

       Register the source code location of BeanPostProcessor:

run() -> 
this.refreshContext(context) -> 
this.refresh(context) -> 
applicationContext.refresh() -> 
this.registerBeanPostProcessors(beanFactory) -> 
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this) 

       Process the source code location of BeanPostProcessor:

run() -> 
this.refreshContext(context) -> 
this.refresh(context) -> 
applicationContext.refresh() -> 
this.finishBeanFactoryInitialization(beanFactory) -> 
beanFactory.preInstantiateSingletons() -> DefaultListableBeanFactory.preInstantiateSingletons() -> 
this.getBean(beanName) -> 
this.doGetBean() -> 
this.createBean(beanName, mbd, args) -> 
AbstractAutowireCapableBeanFactory.createBean() -> 
this.doCreateBean(beanName, mbdToUse, args) -> 
this.initializeBean(beanName, exposedObject, mbd) -> 
this.applyBeanPostProcessorsBeforeInitialization

(2) call

       Look at some of the source code registered by registerBeanPostProcessors:

 public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
    
    
        //从bean工厂获取到bean实现了BeanPostProcessor或者BeanPostProcessor子类的名称集合
        String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
        //注册BeanPostProcessor 
        registerBeanPostProcessors(beanFactory, (List)nonOrderedPostProcessors);
    }

    //注册BeanPostProcessor
    private static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
    
    
        Iterator var2 = postProcessors.iterator();
        while(var2.hasNext()) {
    
    
            BeanPostProcessor postProcessor = (BeanPostProcessor)var2.next();
            beanFactory.addBeanPostProcessor(postProcessor);
        }
    }
 
    //BeanPostProcessor添加到集合中
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
    
    
        this.beanPostProcessors.remove(beanPostProcessor);
        this.beanPostProcessors.add(beanPostProcessor);
    }

       The bean obtained from the bean factory implements a collection of BeanPostProcessor or BeanPostProcessor subclasses, and adds them to the list collection of beanPostProcessors. There are methods in the bean modified by @PostConstruct or @PreDestroy, which will match the CommonAnnotationBeanPostProcessor class. Screenshot below:
insert image description here

       When processing the BeanPostProcessor collection, the postProcessBeforeInitialization method will be called. Take a look at part of the source code of its entry initializeBean method:

 protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    
    

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
    
    
            //遍历BeanPostProcessor集合,执行它的postProcessBeforeInitialization方法
            wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
        }

        try {
    
    
            //执行初始化方法,包含InitializingBean和自定义InitMethod
            this.invokeInitMethods(beanName, wrappedBean, mbd);
        } catch (Throwable var6) {
    
    
            throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
        }

        return wrappedBean;
    }

       The method modified by @PostConstruct will be called when traversing the list to the CommonAnnotationBeanPostProcessor class, so the initialization execution sequence is: @PostConstruct-"InitializingBean interface method-"initMethod method .

Registered in is the CommonAnnotationBeanPostProcessor subclass, and the postProcessBeforeInitialization method is defined in the parent class InitDestroyAnnotationBeanPostProcessor, see part of the source code:

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
        //获取被注解修饰的方法
        InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata metadata = this.findLifecycleMetadata(bean.getClass());
        metadata.invokeInitMethods(bean, beanName);
    }

   public void invokeDestroyMethods(Object target, String beanName) throws Throwable         {
    
    
       for(Iterator var5 = ((Collection)destroyMethodsToUse).iterator();
           var5.hasNext(); element.invoke(target)) {
    
    //使用反射执行方法

       }
    }

       Obtain the method modified by @PostConstruct through the bean, and use reflection to execute the corresponding method.

3. Usage scenarios

       It can be used to initialize resource usage in the project, such as obtaining data from the properties configuration file, but the data format needs to be processed again, which can be realized by using @PostConstruct.

@Configuration
@ConfigurationProperties(prefix="inner.ignored")
@Data
public class ApiWhiteListConfig {
    
    

    //忽略的访问集合,key:ip,value:port
    private Map<String,String> ignoredMap = new HashMap<String,String>();
    private List<String> urlList;

    @PostConstruct
    public void init(){
    
    
        if(null != urlList && urlList.size() > 0){
    
    
            for(int i = 0;i < urlList.size();i++){
    
    
                String str = urlList.get(i);
                String[] arr = str.split(":");
                if(null != arr && arr.length == 2){
    
    
                    ignoredMap.put(arr[0],arr[1]);
                }
             }
        }
    }
}

四、DisposableBean

       DisposableBean is an interface used to do some cleanup when the bean is destroyed.

1. Source code

public interface DisposableBean {
    
    
    void destroy() throws Exception;
}

       There is only one destroy method, and the subclass implements DisposableBean and overrides its method.

2. spring boot source code call

(1) location

       The source code call location for processing this interface is as follows:

run() -> 
this.refreshContext(context) -> 
this.refresh(context) -> 
applicationContext.refresh() -> 
this.finishBeanFactoryInitialization(beanFactory) -> 
beanFactory.preInstantiateSingletons() -> DefaultListableBeanFactory.preInstantiateSingletons() -> 
this.getBean(beanName) -> 
this.doGetBean() -> 
this.createBean(beanName, mbd, args) -> 
AbstractAutowireCapableBeanFactory.createBean() -> 
this.doCreateBean(beanName, mbdToUse, args) -> 
this.registerDisposableBeanIfNecessary(beanName, bean, mbd) ->
this.registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, mbd, this.getBeanPostProcessorCache().destructionAware, acc)) -> 
class DisposableBeanAdapter implements DisposableBean -> 
DisposableBeanAdapter.destroy() -> 
((DisposableBean)this.bean).destroy()

(2) call

       After the bean is initialized, the method registerDisposableBeanIfNecessary will register the DisposableBean, and finally create a DisposableBeanAdapter object. The DisposableBeanAdapter class implements the DisposableBean interface. The way to destroy resources can make the class implement the DisposableBean interface and override the destroy method; you can also use @Bean to declare the bean object, and configure the destruction method through the attribute destroyMethod, for example:

@Configuration
public class BeanConfig {
    
    

    @Scope(value="singleton")
    @Bean(destroyMethod = "destroyMethod")
    public BeanDemo beanDemo(){
    
    
        return new BeanDemo("张三",18);
    }

}

       You can also use the annotation @PreDestroy to execute the method before the bean is destroyed, for example:

    @PreDestroy
    public void preDestroy(){
    
    
        System.out.println("=========【@PreDestroy】的preDestroy()方法===========");
    }

       The execution order of these three methods: @PreDestroy - "DisposableBean - "destroyMethod . You can look at the destruction source code of DisposableBeanAdapter:

    public void destroy() {
    
    
        if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
    
    
            Iterator var1 = this.beanPostProcessors.iterator();

            while(var1.hasNext()) {
    
    
                DestructionAwareBeanPostProcessor processor = (DestructionAwareBeanPostProcessor)var1.next();
                //调用被@PreDestroy注解修饰的方法执行
                processor.postProcessBeforeDestruction(this.bean, this.beanName);
            }
        }

        if (this.invokeDisposableBean) {
    
    
            if (logger.isTraceEnabled()) {
    
    
                logger.trace("Invoking destroy() on bean with name '" + this.beanName + "'");
            }

            try {
    
    
                if (System.getSecurityManager() != null) {
    
    
                    AccessController.doPrivileged(() -> {
    
    
                        ((DisposableBean)this.bean).destroy();
                        return null;
                    }, this.acc);
                } else {
    
    
                    //执行实现了DisposableBean接口的destroy方法
                    ((DisposableBean)this.bean).destroy();
                }
            } catch (Throwable var3) {
    
    
                String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
                if (logger.isDebugEnabled()) {
    
    
                    logger.warn(msg, var3);
                } else {
    
    
                    logger.warn(msg + ": " + var3);
                }
            }
        }

        if (this.destroyMethod != null) {
    
    
            //执行自定义的destroyMethod方法
            this.invokeCustomDestroyMethod(this.destroyMethod);
        } else if (this.destroyMethodName != null) {
    
    
            Method methodToInvoke = this.determineDestroyMethod(this.destroyMethodName);
            if (methodToInvoke != null) {
    
    
                this.invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
            }
        }
    }

       Previously analyzed that when registering beanPostProcessor, the CommonAnnotationBeanPostProcessor class will be registered, and when it is destroyed, it will call the postProcessBeforeDestruction of the parent class InitDestroyAnnotationBeanPostProcessor, and then use reflection to execute the method; then execute the destroy method of the DisposableBean subclass; finally use reflection to execute the custom destroyMethod method.

3. Usage scenarios

       It is used in the xxl-job project to clean up resources, stop created daemon threads, destroy thread pools and other post-work.

@Component
public class XxlJobAdminConfig implements InitializingBean, DisposableBean {
    
    

    // 实现DisposableBean接口,重写它的bean销毁方法
    @Override
    public void destroy() throws Exception {
    
    
        xxlJobScheduler.destroy();
    }
}

5. @PreDestroy

       @PreDestroy is a jdk annotation for cleaning up when resources are destroyed.

1. Source code

@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PreDestroy {
    
    
}

2. spring boot source code call

(1) location

       Consistent with @PostConstruct, see @PostConstruct analysis for details.

(2) call

       It has been analyzed in DisposableBean, see DisposableBean Analysis for details.

Six, BeanPostProcessor

       BeanPostProcessor is an interface. The class implements this interface. After the bean is instantiated and the attribute assignment (populateBean method) is completed, some enhanced processing can be performed before and after initialization. If a certain class implements the BeanPostProcessor interface, all beans in the spring container will call the method rewritten by this class before and after instantiation , which can be used for some verification of all beans or to process some beans individually according to the bean type.

1. Source code

public interface BeanPostProcessor {
    
    
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
        return bean;
    }

    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
        return bean;
    }
}

       Contains two methods, postProcessBeforeInitialization is called before initialization, and postProcessAfterInitialization is called after initialization.

2. spring boot source code call

(1) location

       The source code call location for processing this interface is as follows:

run() -> 
this.refreshContext(context) -> 
this.refresh(context) -> 
applicationContext.refresh() -> 
this.finishBeanFactoryInitialization(beanFactory) -> 
beanFactory.preInstantiateSingletons() -> 
DefaultListableBeanFactory.preInstantiateSingletons() -> 
this.getBean(beanName) -> 
this.doGetBean() -> 
this.createBean(beanName, mbd, args) -> 
AbstractAutowireCapableBeanFactory.createBean() -> 
this.doCreateBean(beanName, mbdToUse, args) -> 
this.initializeBean(beanName, exposedObject, mbd) -> 
this.applyBeanPostProcessorsBeforeInitialization(bean, beanName) -> 
this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)

       The source code location for registering BeanPostProcessor has been given in the introduction of @PostConstruct:

run() -> 
this.refreshContext(context) -> 
this.refresh(context) -> 
applicationContext.refresh() -> 
this.registerBeanPostProcessors(beanFactory) -> 
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this) 

(2) call

       We first define a bean1, and then define a bean2 that implements BeanPostProcessor. In bean2, we can do some processing on bean1 before and after initialization.

       The definition of bean1:

@Component
public class BeanDemo implements InitializingBean, DisposableBean{
    
    
    @Override
    public void destroy() throws Exception {
    
    
        System.out.println("=========【DisposableBean】的destroy()方法===========");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
    
    
        System.out.println("=========【InitializingBean】的afterPropertiesSet()方法===========");
    }
}

       The definition of bean2:

@Component
public class BeanDemo2 implements  BeanPostProcessor {
    
    
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
        if(bean instanceof BeanDemo) {
    
    
            System.out.println("=========【BeanPostProcessor】的postProcessBeforeInitialization()方法===========");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
        if(bean instanceof BeanDemo) {
    
    
            System.out.println("=========【BeanPostProcessor】的postProcessAfterInitialization()方法===========");
        }
        return bean;
    }
}

       When executing the registerBeanPostProcessors method to register BeanPostProcessor, first register the bean that implements the BeanPostProcessor interface, and then register to process the BeanPostProcessor annotated, such as @PostConstruct, and register it in a list collection, so that when traversing the list collection, it will be traversed first A bean that implements the BeanPostProcessor interface. Check out the registration status:
insert image description here
insert image description here

       Look at the source code of the execution sequence of the initializeBean method that initializes the bean:

   protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    
    

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
    
    
            //遍历BeanPostProcessor集合,执行postProcessAfterInitialization方法
            wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
        }

        try {
    
    
            //执行初始化方法,包含InitializingBean和自定义InitMethod
            this.invokeInitMethods(beanName, wrappedBean, mbd);
        } catch (Throwable var6) {
    
    
            throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
        }

        if (mbd == null || !mbd.isSynthetic()) {
    
    
            //遍历BeanPostProcessor集合,执行postProcessAfterInitialization方法
            wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

       From this we can see the initialization execution sequence: BeanPostProcessor implementation class before-"@PostConstruct-"InitializingBean interface method-"initMethod method-"BeanPostProcessor implementation class after .

       Look at the source code of the method of traversing the BeanPostProcessor collection:

    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
    
    
        Object result = existingBean;

        Object current;
        //获取BeanPostProcessor集合
        for(Iterator var4 = this.getBeanPostProcessors().iterator(); var4.hasNext(); result = current) {
    
    
            BeanPostProcessor processor = (BeanPostProcessor)var4.next();
            //执行postProcessBeforeInitialization方法
            current = processor.postProcessBeforeInitialization(result, beanName);
            if (current == null) {
    
    
                return result;
            }
        }

        return result;
    }

七、ApplicationContextAware

       ApplicationContextAware is an interface class. The class implements this interface. You can get the ApplicationContext program context by rewriting its method. According to the program context, you can get the bean object in the spring container, and then perform other processing on the bean according to business requirements.

1. Source code

public interface ApplicationContextAware extends Aware {
    
    
    void setApplicationContext(ApplicationContext var1) throws BeansException;
}

       There is only one setApplicationContext method, and subclasses can override this method to receive ApplicationContext when spring starts.

2. spring boot source code call

(1) location

       The source code call location for processing this interface is as follows:

run() -> 
this.refreshContext(context) -> 
this.refresh(context) -> 
applicationContext.refresh() -> 
AbstractApplicationContext.refresh() -> 
this.prepareBeanFactory(beanFactory) -> 
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)) -> 
ApplicationContextAwareProcessor.postProcessBeforeInitialization() -> 
ApplicationContextAwareProcessor.invokeAwareInterfaces()

(2) call

       The key logic is in this line of code:

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this))

       Add ApplicationContextAwareProcessor to the list collection that stores BeanPostProcessor. ApplicationContextAwareProcessor implements BeanPostProcessor. When spring processes each bean later, it will traverse this collection, call the postProcessBeforeInitialization method of each object, and pass the currently processed bean as a parameter. In the postProcessBeforeInitialization method, it is judged whether the current bean implements the ApplicationContextAware interface, and if it is realized, the bean method is called.

       Look at the method of addBeanPostProcessor:

   private final List<BeanPostProcessor> beanPostProcessors = new AbstractBeanFactory.BeanPostProcessorCacheAwareList();

   public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
    
    
        Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
        this.beanPostProcessors.remove(beanPostProcessor);
        this.beanPostProcessors.add(beanPostProcessor);
    }

       The reason why the BeanPostProcessor is stored in the form of a list is because the list is ordered, and the objects added first are traversed first. This is also the reason why the setApplicationContext method of the bean object is executed first compared to other methods. Add this BeanPostProcessor in the prepareBeanFactory method and add other BeanPostProcessor is in registerBeanPostProcessors, so the order of traversing the BeanPostProcessor collection to execute initialization methods: ApplicationContextAware-"BeanPostProcessor implementation class before-"@PostConstruct-"InitializingBean interface method-"initMethod method-"BeanPostProcessor implementation class after . The following are screenshots of the two entries for registering BeanPostProcessor in the refresh method:
insert image description here

       Analyze part of the source code of the ApplicationContextAwareProcessor#postProcessBeforeInitialization method:

 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
        //判断bean对象的类型是否属于这些aware,都不属于则直接返回bean
        if (!(bean instanceof EnvironmentAware) && !(bean instanceof EmbeddedValueResolverAware) && !(bean instanceof ResourceLoaderAware) && !(bean instanceof ApplicationEventPublisherAware) && !(bean instanceof MessageSourceAware) && !(bean instanceof ApplicationContextAware) && !(bean instanceof ApplicationStartupAware)) {
    
    
            return bean;
        } else {
    
    
            AccessControlContext acc = null;
            if (System.getSecurityManager() != null) {
    
    
                acc = this.applicationContext.getBeanFactory().getAccessControlContext();
            }

            if (acc != null) {
    
    
                AccessController.doPrivileged(() -> {
    
    
                    this.invokeAwareInterfaces(bean);
                    return null;
                }, acc);
            } else {
    
    
                //执行aware方法
                this.invokeAwareInterfaces(bean);
            }

            return bean;
        }
    }

    //根据bean对象是哪种类型,强制转成需要的类型,调用它定义的方法
    private void invokeAwareInterfaces(Object bean) {
    
    
        if (bean instanceof EnvironmentAware) {
    
    
            ((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());
        }

        if (bean instanceof ApplicationContextAware) {
    
    
            ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
        }

    }

       Determine whether the type of the bean object belongs to these aware, if not, return the bean directly, among them, judge the type of ApplicationContextAware, including the awareness that needs to be processed, then according to the type of the bean object, force it into the required type, and call it The defined method, like setApplicationContext is the method of the ApplicationContextAware interface. The class implements the ApplicationContextAware interface, rewrites setApplicationContext to receive the applicationContext, and at this stage will call the setApplicationContext method of the implementation class.

3. Usage scenarios

       It is used in the xxl-job open source project. It is necessary to obtain the @XxlJob annotation modified method in the bean object from the spring container, add these methods to the map collection, and when the timer is called to a specific task, through reflection Execution method. To obtain the bean object, you need to use the applicationContext context, so implement the ApplicationContextAware interface and rewrite setApplicationContext to receive the applicationContext. Look at some of the source code:

public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationContextAware, SmartInitializingSingleton, DisposableBean {
    
    
   private static ApplicationContext applicationContext;

    //实现ApplicationContextAware接口,获取上下文,得到加载到spring容器中的所有bean对象
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        XxlJobSpringExecutor.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
    
    
        return applicationContext;
    }
}

8. Bean initialization and destruction process

     After the above analysis, it can be seen that when spring starts, the initialization process is: add ApplicationContextAwareProcessor to the list collection - "bean implements BeanPostProcessor, then add this bean to the list collection -" add CommonAnnotationBeanPostProcessor to the list collection - "When initializing the bean Traverse the list and call the postProcessBeforeInitialization method of each BeanPostProcessor - "according to the order of adding the list, execute ApplicationContextAware, BeanPostProcessor, CommonAnnotationBeanPostProcessor (@PostConstruct) -" execute the InitializingBean interface method - "execute the custom initMethod method -" traverse the list and call each BeanPostProcessor The postProcessAfterInitialization method - "Execute the SmartInitializingSingleton interface method .

       Bean initialization flow chart:
insert image description here

       Bean destruction flow chart:
insert image description here

       Let's look at a demo and verify it according to the output:

       bean1 definition:

@Configuration
public class BeanConfig {
    
    

    @Scope(value="singleton")
    @Bean(initMethod = "intMethod",destroyMethod = "destroyMethod")
    public BeanDemo beanDemo(){
    
    
        return new BeanDemo("张三",18);
    }
}

public class BeanDemo implements ApplicationContextAware, SmartInitializingSingleton, InitializingBean, DisposableBean{
    
    

    private String name;
    private Integer age;

    public BeanDemo(String name, Integer age) {
    
    
        this.name = name;
        this.age = age;
        System.out.println("=========【BeanDemo】的有参构造方法===========");
    }

    @Override
    public void destroy() throws Exception {
    
    
        System.out.println("=========【DisposableBean】的destroy()方法===========");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
    
    
        System.out.println("=========【InitializingBean】的afterPropertiesSet()方法===========");
    }

    @Override
    public void afterSingletonsInstantiated() {
    
    
        System.out.println("=========【SmartInitializingSingleton】的afterSingletonsInstantiated()方法===========");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        System.out.println("=========【ApplicationContextAware】的setApplicationContext()方法===========");
    }

    public void intMethod(){
    
    
        System.out.println("=========【intMethod】的intMethod()方法===========");
    }

    public void destroyMethod(){
    
    
        System.out.println("=========【destroyMethod】的destroyMethod()方法===========");
    }

    @PreDestroy
    public void preDestroy(){
    
    
        System.out.println("=========【@PreDestroy】的preDestroy()方法===========");
    }

    @PostConstruct
    public void postConstruct(){
    
    
        System.out.println("=========【@PostConstruct】的postConstruct()方法===========");
    }
}

       bean2 definition:

@Component
public class BeanDemo2 implements  BeanPostProcessor {
    
    

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
        if(bean instanceof BeanDemo) {
    
    
            System.out.println("=========【BeanPostProcessor】的postProcessBeforeInitialization()方法===========");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
        if(bean instanceof BeanDemo) {
    
    
            System.out.println("=========【BeanPostProcessor】的postProcessAfterInitialization()方法===========");
        }
        return bean;
    }
}

       The output when the program starts:
insert image description here

       Program result output result:
insert image description here

Guess you like

Origin blog.csdn.net/ZHANGLIZENG/article/details/131131998