源码分析spring容器启动销毁资源

news2024/11/25 3:00:07

文章目录

      • 一、InitializingBean
      • 二、SmartInitializingSingleton
      • 三、@PostConstruct
      • 四、DisposableBean
      • 五、@PreDestroy
      • 六、BeanPostProcessor
      • 七、ApplicationContextAware
      • 八、Bean初始化销毁过程

       spring项目启动时,在bean的生命周期内,可以添加一些前置、后置处理,也可用于资源初始化、资源销毁。本文结合着源码对spring的一些扩展功能,执行顺序进行分析。

一、InitializingBean

       InitializingBean是一个接口,类实现了此接口,重写afterPropertiesSet方法,可以在bean实例化、属性赋值(populateBean方法)之后进行一些处理。

1.源码

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

       只包含一个afterPropertiesSet方法,子类实现了接口需要实现此方法。

2.spring boot源码调用

(1)位置

       处理此接口的源码调用位置如下:

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)调用

       在bean进行初始化的时候,会执行invokeInitMethods初始化的方法,这个方法里面处理了对InitializingBean接口的afterPropertiesSet方法、用户自定义的初始化方法。用户自定义的方法指的是通过注解@Bean来申明一个bean时使用initMethod属性来指定的方法,申明bean除了@Bean还有@Component,@Component只能配置bean的名称,它可以直接在类上使用,spring容器会把它加载为一个bean;@Bean需要放在配置类(@Configuration修饰)中,放在基础类中spring是扫描不到的。

       @Component源码:

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

       使用@Bean配置自定义初始化方法:

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

       一个类既实现了InitializingBean接口,又配置了自定义initMethod方法,它的执行顺序是:先InitializingBean接口的方法-》initMethod方法,从invokeInitMethods方法源码可以看出:

  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.使用场景

       在xxl-job项目中有使用,通过afterPropertiesSet方法来初始化定时守护线程、创建线程池等。看下部分源码:

@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是一个接口,类实现了此接口,可以在bean实例化、初始化完成后进行后置处理,要求bean为单例且非懒加载的方式才会触发方法的执行,通过注解@Scope来指定bean为单例还是多实例,值为singleton:单例(全局有且只有一个实例),值为prototype:多实例(每次获取bean都是一个新实例),使用@Bean或者@Component声明的bean默认是单例的。

1.源码

public interface SmartInitializingSingleton {
    void afterSingletonsInstantiated();
}

       只有一个afterSingletonsInstantiated方法,子类可以实现此方法,进行资源的初始化。

2.spring boot源码调用

(1)位置

       处理此接口的源码调用位置如下:

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

(2)调用

       当bean已经完成实例化、初始化并执行完初始方法后才会处理SmartInitializingSingleton,使用while(true)来处理bean,先通过getBean实例化、初始化bean,并保存到缓存中,最后从缓存中取出bean,处理类型为SmartInitializingSingleton的bean,调用它的afterSingletonsInstantiated方法,所以此方法是bean初始化最后执行的方法。看下源码处理:

  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.使用场景

       在xxl-job项目中有使用,当bean已经初始化完成,把bean中被@XxlJob修饰的方法添加到map集合中,初始化了netty服务器和线程池等。看下部分源码:

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是jdk的注解,也是用于初始化资源使用,spring使用InitDestroyAnnotationBeanPostProcessor对@PostConstruct、@PreDestroy注解进行包装,这样就可以使用BeanPostProcessor对使用了@PostConstruct、@PreDestroy修饰的方法进行调用。

1.源码

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

2.spring boot源码调用

(1)位置

       先看InitDestroyAnnotationBeanPostProcessor类的源码:

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;
    }
}

       InitDestroyAnnotationBeanPostProcessor类实现了MergedBeanDefinitionPostProcessor接口,里面有两个类型为Annotation的属性,Annotation是所有注解的父类即@PostConstruct的父类,initAnnotationType用于标识接收初始化注解的类型,destroyAnnotationType用于标识接收销毁注解的类型,具体接收哪个注解由InitDestroyAnnotationBeanPostProcessor的子类CommonAnnotationBeanPostProcessor来实现。

       看下CommonAnnotationBeanPostProcessor部分源码:

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

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

        CommonAnnotationBeanPostProcessor类的默认构造函数设置了 initAnnotationType的类型为PostConstruct,destroyAnnotationType类型为PreDestroy。

       在注册BeanPostProcessor时,会向beanPostProcessors这个list集合添加一个CommonAnnotationBeanPostProcessor,这样在后面遍历beanPostProcessors集合执行postProcessBeforeInitialization方法时,会调用到InitDestroyAnnotationBeanPostProcessor类的postProcessBeforeInitialization方法,此方法通过反射执行被@PostConstruct修饰的方法。

       注册BeanPostProcessor的源码位置:

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

       处理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)调用

       看下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);
    }

       从bean工厂获取到bean实现了BeanPostProcessor或者BeanPostProcessor子类的集合,把他们添加到beanPostProcessors这个list集合中,bean中有方法被@PostConstruct或者@PreDestroy修饰,会匹配到CommonAnnotationBeanPostProcessor类。截图如下:
在这里插入图片描述

       在处理BeanPostProcessor集合时会调用到postProcessBeforeInitialization方法,看下它的入口initializeBean方法部分源码:

 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;
    }

       被@PostConstruct修饰的方法,遍历list到CommonAnnotationBeanPostProcessor类时会被调用,所以初始化执行顺序为:@PostConstruct-》InitializingBean接口的方法-》initMethod方法

注册进去的是CommonAnnotationBeanPostProcessor子类,postProcessBeforeInitialization方法定义在父类InitDestroyAnnotationBeanPostProcessor中,看下部分源码:

    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)) {//使用反射执行方法

       }
    }

       通过bean获取到被@PostConstruct修饰的方法,使用反射执行对应的方法。

3.使用场景

       项目中可以用于初始化资源使用,例如从properties配置文件中获取到数据,但是数据格式需要再处理一下,可以使用@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是一个接口,用于bean销毁时做一些清理工作。

1.源码

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

       只有一个destroy方法,子类实现DisposableBean,重写它的方法。

2.spring boot源码调用

(1)位置

       处理此接口的源码调用位置如下:

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)调用

       在bean进行初始化完成后,方法registerDisposableBeanIfNecessary会注册DisposableBean,最终创建一个DisposableBeanAdapter对象,DisposableBeanAdapter类实现了DisposableBean接口。销毁资源的方式可以让类实现DisposableBean接口,重写destroy方法;也可以使用@Bean的方式声明bean对象,通过属性destroyMethod配置销毁方法,例如:

@Configuration
public class BeanConfig {

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

}

       也可以使用注解@PreDestroy在bean销毁之前执行方法,例如:

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

       这三种方法的执行顺序:@PreDestroy -》 DisposableBean-》destroyMethod。可以看下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));
            }
        }
    }

       前面分析了在注册beanPostProcessor时,会注册CommonAnnotationBeanPostProcessor类,当销毁时会调用到父类InitDestroyAnnotationBeanPostProcessor的postProcessBeforeDestruction,然后使用反射执行方法;再执行DisposableBean子类的destroy方法;最后使用反射执行自定义的destroyMethod方法。

3.使用场景

       在xxl-job项目中就有使用,用于清理资源,停止创建的守护线程,销毁线程池等后置工作。

@Component
public class XxlJobAdminConfig implements InitializingBean, DisposableBean {

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

五、@PreDestroy

       @PreDestroy是jdk的注解,用于销毁资源时的清理工作。

1.源码

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

2.spring boot源码调用

(1)位置

       与@PostConstruct一致,详见@PostConstruct分析。

(2)调用

       在DisposableBean中已经分析,详见DisposableBean分析。

六、BeanPostProcessor

       BeanPostProcessor是一个接口,类实现了此接口,可以在bean实例化、属性赋值(populateBean方法)完成后,在开始进行初始化之前、初始化之后进行一些加强处理。某个类实现了BeanPostProcessor接口,则spring容器中所有bean进行实例化前后都会调用这个类重写的方法,可以用于所有bean的一些校验或者根据bean类型单独处理某些bean。

1.源码

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;
    }
}

       包含两个方法,postProcessBeforeInitialization初始化之前调用,postProcessAfterInitialization初始化之后调用。

2.spring boot源码调用

(1)位置

       处理此接口的源码调用位置如下:

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)

       在@PostConstruct介绍时已经给出注册BeanPostProcessor的源码位置:

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

(2)调用

       我们先定义一个bean1,再定义一个实现了BeanPostProcessor的bean2,在bean2中可以对bean1初始化前后做一些处理。

       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()方法===========");
    }
}

       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;
    }
}

       在执行registerBeanPostProcessors方法注册BeanPostProcessor的时候,先注册的是实现了BeanPostProcessor接口的bean,再注册处理例如@PostConstruct注解的BeanPostProcessor,而注册到的是一个list集合中,这样在遍历list集合的时候,优先遍历实现了BeanPostProcessor接口的bean。看下注册的情况:
在这里插入图片描述
在这里插入图片描述

       看下初始化bean的initializeBean方法执行顺序部分源码:

   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;
    }

       从这可以看出初始化执行顺序:BeanPostProcessor实现类before-》@PostConstruct-》InitializingBean接口的方法-》initMethod方法-》BeanPostProcessor实现类after

       看下遍历BeanPostProcessor集合的方法源码:

    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是一个接口类,类实现了此接口,重写它的方法即可获取ApplicationContext程序上下文,根据程序上下文可以获取到spring容器中的bean对象,然后根据业务需求对bean进行其他处理。

1.源码

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

       只有一个setApplicationContext方法,子类重写此方法,在spring启动时即可接收ApplicationContext。

2.spring boot源码调用

(1)位置

       处理此接口的源码调用位置如下:

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

(2)调用

       关键的逻辑在这一行代码:

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this))

       向存放BeanPostProcessor的list集合中加入ApplicationContextAwareProcessor,ApplicationContextAwareProcessor实现了BeanPostProcessor,后面spring处理每个bean时,会对这个集合进行遍历,调用每个对象的postProcessBeforeInitialization方法,并把当前处理的bean作为参数传递进去,在postProcessBeforeInitialization方法中判断当前bean是否实现了ApplicationContextAware接口,实现了则进行bean方法的调用。

       看下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);
    }

       之所以使用list形式存放BeanPostProcessor是因为list是有序的,先加入的对象先遍历到,这也是bean对象的setApplicationContext方法相比其他方法先执行的原因,添加这个BeanPostProcessor在prepareBeanFactory方法中,添加其他的BeanPostProcessor在registerBeanPostProcessors中,所以遍历BeanPostProcessor集合执行初始化方法的顺序:ApplicationContextAware-》BeanPostProcessor实现类before-》@PostConstruct-》InitializingBean接口的方法-》initMethod方法-》BeanPostProcessor实现类after。下面是refresh方法中注册BeanPostProcessor的两个入口截图:
在这里插入图片描述

       分析下ApplicationContextAwareProcessor#postProcessBeforeInitialization方法部分源码:

 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);
        }

    }

       判断bean对象的类型是否属于这些aware,都不属于则直接返回bean,其中就有判断ApplicationContextAware类型的,包含需要处理的aware,则根据bean对象是哪种类型,强制转成需要的类型,调用它定义的方法,像setApplicationContext就是ApplicationContextAware接口的方法,类实现了ApplicationContextAware接口,重写setApplicationContext接收applicationContext,在这个阶段就会调用到实现类的setApplicationContext方法。

3.使用场景

       在xxl-job开源项目中就有使用,需要从spring容器中获取bean对象中使用了@XxlJob注解修饰的方法,把这些方法添加到map集合中,当定时器调用到具体的任务时,通过反射执行方法。需要获取bean对象就需要使用applicationContext上下文,所以实现ApplicationContextAware接口,重写setApplicationContext接收applicationContext。看下部分源码:

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;
    }
}

八、Bean初始化销毁过程

     经过上面的分析,可以看出在spring启动时,初始化的流程为:添加ApplicationContextAwareProcessor到list集合中-》bean实现BeanPostProcessor则添加这个bean到list集合中-》添加CommonAnnotationBeanPostProcessor到list集合中-》初始化bean时遍历list,调用每个BeanPostProcessor的postProcessBeforeInitialization方法-》按list的加入顺序,执行ApplicationContextAware、BeanPostProcessor、CommonAnnotationBeanPostProcessor(@PostConstruct)-》执行InitializingBean接口方法-》执行自定义initMethod方法-》遍历list,调用每个BeanPostProcessor的postProcessAfterInitialization方法-》执行SmartInitializingSingleton接口方法

       bean初始化流程图:
在这里插入图片描述

       bean销毁流程图:
在这里插入图片描述

       来看一个demo,根据输出结果验证一下:

       bean1定义:

@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定义:

@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;
    }
}

       程序启动时输出结果:
在这里插入图片描述

       程序结果输出结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/627975.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ATE测试工程师的前景怎么样?能转DFT工程师吗?

最近后台不少同学私信想要咨询ATE这个岗位&#xff0c;想了解这个岗位的薪资&#xff0c;前景&#xff0c;以及相关的技能&#xff0c;下面就来一起了解一下~ 什么是ATE&#xff1f; ATE是&#xff08;Automatic Test Equipment&#xff09;的缩写&#xff0c; 于半导体产业意…

OOD 使用基于提示的特征映射生成用于视频异常检测

paper link 本文提出了使用提示引导特征映射的生成式视频异常检测框架&#xff0c;作者来自中山大学&#xff0c;文章发表在cvpr2023 作者首先分析了现有方法并指出当前面临的两个问题 两个关键挑战 大多数视频异常检测方法通过在训练阶段学习正常事件的分布,并在测试阶段检…

别找了!前端那些好用的网站都在这里了!【文末送书】

&#x1f340;前言 好用的网站千千万万&#xff0c;如果你还发现好用的网站&#xff0c;欢迎在评论区中留言分享&#x1f601;&#xff0c;赠书活动在文末哟&#xff0c;中奖者可以从给出的五本书中任意挑选自己喜欢的那本 文章目录 &#x1f340;前言 &#x1f340;一、渐变…

简化 Hello World:Java 新写法要来了

OpenJDK 的 JEP 445 提案正在努力简化 Java 的入门难度。 这个提案主要是引入 “灵活的 Main 方法和匿名 Main 类” &#xff0c;希望 Java 的学习过程能更平滑&#xff0c;让学生和初学者能更好地接受 Java 。 提案的作者 Ron Pressler 解释&#xff1a;现在的 Java 语言非常…

快速上手Flutter

目录 一、Flutter介绍 1.高效开发 2.优异的性能 3.较低的开发成本 4.社区活跃 二、Flutter使用 1.Dart 语言 2.什么是Dart语言 3.Flutter 组件库 4.Layout 布局 5.Flutter 工具 6.Flutter社区 三、Flutter使用技巧 四、总结 一、Flutter介绍 Flutter是谷歌的移动…

[CKA]考试之节点维护-指定 node 节点不可用

由于最新的CKA考试改版&#xff0c;不允许存储书签&#xff0c;本博客致力怎么一步步从官网把答案找到&#xff0c;如何修改把题做对&#xff0c;下面开始我们的 CKA之旅 题目为&#xff1a; Task 将k8s-node1节点设置为不可用&#xff0c;然后重新调度该节点上的所有Pod 注…

优维低代码实践:模板

优维低代码技术专栏&#xff0c;是一个全新的、技术为主的专栏&#xff0c;由优维技术委员会成员执笔&#xff0c;基于优维7年低代码技术研发及运维成果&#xff0c;主要介绍低代码相关的技术原理及架构逻辑&#xff0c;目的是给广大运维人提供一个技术交流与学习的平台。 优维…

如何提高测试用例的编写效率?

1、提高测试覆盖率 我们通过对测试用例的评审&#xff0c;进一步完善测试覆盖率。在评审过程中&#xff0c;不同的评审专家看待问题的角度不完全一致&#xff0c;因此我们需要充分考虑测试方法&#xff0c;扩充测试用例的全面性&#xff0c;确保基本功能和核心功能的覆盖率。 如…

操作系统课后题答案(费翔林)

仅为老师布置的课后题答案&#xff0c;仅供学习参考 习题2

数据的存储方式(Parquet、ORC)

文章目录 数据的存储方式按行存储按列存储 Parquest文件布局概念并行处理的单元 配置Row Group Size 行组的大小Data Page Size 数据页的大小 元数据数据页Hive下的Parquet实验Parquet简单工具的使用支持的组件 Apache ORC文件布局Stripe Hive下的Parquet实验ORC简单工具的使用…

NLP——part of speech (POS)中的隐马尔可夫模型 + Viterbi 算法

文章目录 POS隐马尔可夫模型计算简介转移概率矩阵&#xff08;Transition matrix&#xff09;观察矩阵&#xff08;Observation / emission Matrix&#xff09;预测 predictionVitervi 算法练习 POS 词性标注&#xff08;Part-of-Speech Tagging&#xff0c;POS Tagging&#…

【AUTOSAR-Code调试】:Wdog

【AUTOSAR-Code调试】&#xff1a;Wdog DavinciCfg 生成文件添加进GreenHill编译添加.c文件添加.h文件路径 接上篇【Davinci开发】&#xff1a;Wdg配置 DavinciCfg 生成文件添加进GreenHill编译 添加.c文件 添加.h文件路径

模拟实现 Spring AOP

文章目录 前言Spring AOPSpring AOP 概述Spring IoC 技术难点Spring IoC 框架思考需求分析 Spring IoC 技术难点实现模拟实现 AOP 具体代码 前言 Spring 是一种 Java 开发框架&#xff0c;其主要功能有两个&#xff1a;IoC(DI)和AOP。《模拟实现Spring AOP》是本人的一个编程训…

基于SSM的校园二手交易平台

一、源码获取&#xff1a; 链接点击直达&#xff1a;下载链接 二、系统架构&#xff1a; 使用技术&#xff1a; SpringSpringMVCMybatis 三、系统需求分析&#xff1a; 在如今的大学校园中&#xff0c;伴随着学生的购买能力的提高和每年的升学和毕业&#xff0c;存在许多…

调用阿里云API实现证件照生成

目录 1. 作者介绍2. 算法介绍2.1 阿里云介绍2.2 证件照生成背景2.3 图像分割算法 3.调用阿里云API进行证件照生成实例3.1 准备工作3.2 实验代码3.3 实验结果与分析 参考&#xff08;可供参考的链接和引用文献&#xff09; 1. 作者介绍 王逸腾&#xff0c;男&#xff0c;西安工…

ASEMI代理英飞凌TLD5097EL:理解和使用LED驱动器的综合指南

编辑-Z TLD5097EL是一款创新的LED驱动器&#xff0c;在照明行业掀起了波澜。这项先进的技术提供了广泛的好处&#xff0c;包括提高能源效率、延长使用寿命和增强性能。在本综合指南中&#xff0c;我们将探讨TLD5097EL的功能和优点&#xff0c;并提供如何有效利用该LED驱动器优…

python -- 绘制colorbar时设置标签为居中显示

python – 绘制colorbar时设置标签为居中显示 在海洋气象领域的相关研究中&#xff0c;对于一些异常信号的二维填色图绘制时&#xff0c;通常在设置colorbar都是以0为中心对称分布的。而在绘制colorbar时&#xff0c;由于存在负号会使得默认colorbar标签不太好看&#xff08;强…

window服务器环境将springboot jar包安装成一个window服务自启动

目录 1.下载WinSW工具 下载winswhttps://github.com/winsw/winsw/releases 2.新建一个Window Service信息的xml文件 3.将xml和exe重命名 4.安装卸载服务 5.修改配置文件 6.常用命令(注意winsw是exe名字 1.下载WinSW工具 下载winswhttps://github.com/winsw/winsw/rele…

图像降噪网络:KBNet 论文笔记

0 前言 Zhang Y, Li D, Shi X, et al. KBNet: Kernel Basis Network for Image Restoration[J]. arXiv preprint arXiv:2303.02881, 2023. https://arxiv.org/abs/2303.02881 论文主要提出了 Kernel Basis Attention Module 注意力模块&#xff0c;称为 KBA 模块。该模块可以轻…

[中阳期货】端午都有哪些习俗,为什么不能说快乐?

端午节&#xff08;屈原故里端午习俗&#xff09;&#xff0c;流行于湖北省宜昌市、秭归县的传统民俗&#xff0c;国家级非物质文化遗产之一。 “五月五&#xff08;农历&#xff09;&#xff0c;过端午。”端午节是中华民族的传统节日。《续齐谐记》、《荆楚岁时记》载&#x…