目的

spring提供了三种初始化方法:
1、@PostConstruct、@PreDestory
2、实现 InitializingBean DisposableBean 接口,并实现对应的afterPropertiesSet()和destroy()方法
3、设置init-method和destory-method
本文主要解析三个初始化和销毁方法的源码

只是有一个点需要注意:@PostConstruct、@PreDestory这两个注解是通过后置处理器完成处理的 --> org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization

其他两种方式,不是通过后置处理器完成的

源码

1、三种初始化方法的优先级从高到低;在spring官方文档也有明确指出

Multiple lifecycle mechanisms configured for the same bean, with
different initialization methods, are called as follows:Methods annotated with @PostConstructafterPropertiesSet() as defined by the InitializingBean callback interfaceA custom configured init() method
Destroy methods are called in the same order:Methods annotated with @PreDestroydestroy() as defined by the DisposableBean callback interfaceA custom configured destroy() method

优先级之所以是这样,和源码中对三种配置方式处理的优先级有关系

测试代码

public class UserService04 implements InitializingBean,DisposableBean {public UserService04() {}@Overridepublic void destroy() throws Exception {System.out.println("实现接口DisposableBean销毁");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("实现接口InitializingBean初始化");}public void init(){System.out.println("initMethod");}public void destroyConfig(){System.out.println("destroyMethod");}@PostConstructpublic void testPost(){System.out.println("注解PostConstruct init");}@PreDestroypublic void testDestroy(){System.out.println("注解PreDestroy 销毁");}
}@Configuration
@ComponentScan("com.springsource.initmethod")
public class InitMethodConfig {@Bean(initMethod = "init",destroyMethod = "destroyConfig")public UserService04 testUserService04(){return new UserService04();}
}

2、初始化方法
初始化方法的代码位置是在

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)

在该方法中,完成了bean的初始化方法回调和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);
}

对于@PostConstruct和@PreDestroy这两个注解,是在applyBeanPostProcessorsBeforeInitialization()中完成处理的,而剩下两种初始化方法,是在invokeInitMethods()中完成的,所以,对于注解的方式,优先级最高

我们先来说invokeInitMethods()方法,也就是后两种初始化方法:

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)throws Throwable {//这里是处理实现了InitializingBean接口的初始化方法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 {// 调用实现类中的afterPropertiesSet()方法((InitializingBean) bean).afterPropertiesSet();}}//这里是来处理init-method方法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);}}
}

可以看到,代码中是先判断当前bean是否是InitializingBean的实现类,然后优先调用了afterProperties();
然后再调用beanDefinition中对应的initMethod;需要说明的是:initMethod这种方式,对应的初始化方法和销毁方法,是在将bean添加到beanDefinitionMap中的时候,对bean进行了解析,获取到对应的initMethod和destroyMethod,然后放到了beanDefinition中

我们接着来说@PostConstruct和@PreDestroy注解的处理
该注解是由CommonAnnotationBeanPostProcessor的postProcessBeforeInitialization和postProcessBeforeDestruction来处理的

@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {/*** 在初始化bean的时候,会在这里处理注解的初始化方法 @PostConstruct* 从cache中获取到当前bean的元对象* 在invokeInitMethods方法中,就是*/LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());try {metadata.invokeInitMethods(bean, beanName);}catch (InvocationTargetException ex) {throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());}catch (Throwable ex) {throw new BeanCreationException(beanName, "Failed to invoke init method", ex);}return bean;
}

这是初始化方法对应的处理类,在此之前,在第三个后置处理器调用的时候,会调用到org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessMergedBeanDefinition;在该方法中,会找出当前bean中对应的@PostConstruct和@PreDestroy注解对应的方法,存入到lifecycleMetadataCache这个map中

然后在调用postProcessBeforeInitialization()方法的时候,注解从map中遍历所有的初始化方法,然后依次调用

3、销毁方法
三个销毁方法是在调用

@Override
public void destroy() {if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {//这里是处理@PreDestroy注解对应的方法processor.postProcessBeforeDestruction(this.bean, this.beanName);}}if (this.invokeDisposableBean) {if (logger.isDebugEnabled()) {logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'");}try {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {((DisposableBean) this.bean).destroy();return null;}, this.acc);}else {// 处理实现了DisposableBean接口的类((DisposableBean) this.bean).destroy();}}catch (Throwable ex) {String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";if (logger.isDebugEnabled()) {logger.warn(msg, ex);}else {logger.warn(msg + ": " + ex);}}}if (this.destroyMethod != null) {//处理destroyMethod方法invokeCustomDestroyMethod(this.destroyMethod);}else if (this.destroyMethodName != null) {Method methodToCall = determineDestroyMethod(this.destroyMethodName);if (methodToCall != null) {invokeCustomDestroyMethod(methodToCall);}}
}


调用链是这样的,可以看到,在销毁bean的时候,也是按照文章开头的顺序来进行销毁的;而对应的原理和初始化方法调用的原理是一样的

spring源码--第七个后置处理器的使用:初始化方法相关推荐

  1. spring源码:九大后置处理器

    目的: spring在完成一个bean的初始化.实例化的过程中,会用到九个后置处理器:本文梳理出这九个后置处理器 九大后置处理器 spring在初始化的过程中,会在九个地方分别调用了五个后置处理的九个 ...

  2. Spring源码分析系列——bean创建过程分析(三)——工厂方法创建bean

    前言 spring创建bean的方式 测试代码准备 createBeanInstance()方法分析 instantiateUsingFactoryMethod()方法分析 总结 spring创建be ...

  3. 通过Spring的BeanPostProcessor的 bean的后置处理器会拦截所有bean创建过程

    postProcessBeforeInitialization 在init方法之前调用 postProcessAfterInitialization 在init方法之后调用 package com.C ...

  4. Spring源码解析(七)-Bean属性间的循环依赖

    首先复习一下前面学习的Spring容器启动的大致流程,首先Spring会先扫描所有需要实例化的Bean,将这些Bean的信息封装成一个个BeanDefinition,然后注册到BeanDefiniti ...

  5. 筑基期第一式:深入Spring源码之第二节getBean全流程【循环依赖分析+扩展点分析】

    getBean整体逻辑 AbstractBeanFactory#doGetBean方法 protected <T> T doGetBean(String name, @Nullable C ...

  6. Spring源码|解析深入Spring源码多图剖析@Configuration背后的BeanFactory后置处理器实现逻辑

    揭秘@Configuration的秘密之BeanFactory后置处理器 前序文章 Spring如何扫描工作目录下的Bean?|图文并茂讲解@Configuration的工作原理 文章目录 揭秘@Co ...

  7. Spring源码-AOP(六)-自动代理与DefaultAdvisorAutoProxyCreator

    2019独角兽企业重金招聘Python工程师标准>>> Spring AOP 源码解析系列,建议大家按顺序阅读,欢迎讨论 Spring源码-AOP(一)-代理模式 Spring源码- ...

  8. Spring源码整体分析

    spring 架构原理图 核心注解 常用注解 @Bean 使用 @Bean + @Configuration 的形式可以替代 xml 配置文件的形式 @Import @Import:指示要导入的一个或 ...

  9. 框架源码专题:springIOC的加载过程,bean的生命周期,结合spring源码分析

    文章目录 1.BeanFactory和ApplicationContext的区别? 2. IOC与 Bean的加载过程 ①:初始化容器DefaultListableBeanFactory ②:创建读取 ...

  10. 从Spring源码探究AOP代码织入的过程

    随着不断地使用Spring,以及后续的Boot.cloud,不断的体会到这个拯救Java的生态体系的强大,也使我对于这个框架有了极大的好奇心,以至于产生了我为什么不能写一个这样的框架的思考. 通过自学 ...

最新文章

  1. 如何理解Return的返回值?
  2. python什么时候进入中国-python什么时候发明的
  3. Temporal Segment Networks(TSN)实验及错误日志
  4. JDBC的CRUD操作之PreparedStatement的查询操作
  5. python的learn_Python_learn_1day
  6. python:校验邮箱格式
  7. 关于CXF大文件的传输问题
  8. python盒中取球_在Python中找到占据给定球的盒子的位置
  9. UVA 11107 Life Forms——(多字符串的最长公共子序列,后缀数组+LCP)
  10. 基于Android的健康打卡系统,基于Android平台的个人健康管理系统
  11. cad怎样弄出放线的坐标_不知道如何定位放线?今天教大家一个快速准确放线方法(含实例)...
  12. 微信中调用扫一扫最简便的方法 5行代码实现H5扫一扫 HTML5扫二维码最简便的办法
  13. Swift - URL转码解码
  14. 【递归算法】递归算法的快速入门
  15. 阳春三月,放飞希望---希望今年不再碌碌无为
  16. win10怎么设置动态壁纸
  17. kakfa如何查询指定消费组lag
  18. 数字和字符的对照关系表(编码表)
  19. Android TimeoutException治理
  20. 抗锯齿和走样(笔记)

热门文章

  1. 残差网络 ResNet 为什么能训练出1000层的模型 动手学深度学习v2
  2. presto执行一条查询分为七步
  3. 高级优化方法fminunc----吴恩达机器学习
  4. 【机器学习系列】隐马尔科夫模型第一讲:通俗易懂概述HMM
  5. a ppt of CRF
  6. 基于IDEA使用Spark API开放Spark程序(1)
  7. 是新最全Git命令大全及速记图
  8. 【Nowcoder - 5666 H Minimum-cost Flow】2020牛客暑期多校训练营(第一场)【最小费用流变形】
  9. 计算机图形学完整笔记(四):消隐
  10. 32位程序如何在64位系统上运行_32位支持:使用 GCC 交叉编译 | Linux 中国