spring源码解析之---BeanPostProcessor解析

1. 解释

BeanPostProcessor 就是Bean 的后置处理器 ,主要作用就是 Bean 实例之后,在 initialization 之前和之后 调用自定义的方法 改变一些属性
这里 的 initialization 包含: Bean 里面定义的 initMethod , InitializingBean 的 afterPropertiesSet

此外 还有一个 annotation @PostConstruct 和 @PreDestroy,也是可以对Bean 进行扩展的,但是他们的逻辑 和上面的 InitializingBean 和 自定义 的initMethod 的 底层一点点区别,他们 类似 BeanPostProcessor ,他对应的 类是 CommonAnnotationBeanPostProcessor

看一下 BeanPostProcessor 的接口
我用的 是 spring-beans: 5.1.7.RELEASE 版本,下面两个方法都加了 default

/**
主要作用就是 :允许对 Bean instances 自定义修改
ApplicationContexts 会自动 检查到 BeanPostProcessor beans 并将它们应用于随后创建的任何bean
*/
public interface BeanPostProcessor {
    /**
    * 在 进行调用 initialization 方法之前 先运行此方法,这里的 initialization 比如 
    *  (InitializingBean's {@code afterPropertiesSet},或者 or 自定义的 init-method
	* 默认是返回Bean 本身 
    */
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

    /**
    * 在 进行调用 initialization 方法之后 运行此方法, 这里的 initialization 比如 
    *  (InitializingBean's {@code afterPropertiesSet},或者 or 自定义的 init-method
    * 如果是 FactoryBean, 那么 此方法不仅作用于FactoryBean 实例,还作用于 此FactoryBean 创建的对象(自从 spring 2.0 ) ,此post-processor  通过 相应的check 可以决定是作用于 FactoryBean 还是 创建的对象,或者两者
	* 默认是返回Bean 本身 
    */
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

2. demo

2.1 common Demo

  1. 创建一个Bean
@Configuration
public class BeanA {
    private static final Logger log = LoggerFactory.getLogger(BeanA.class);

    public BeanA() {
        System.out.println("=======Bean A  构造函数======");
    }

}
  1. 创建一个自定义的BeanPostProcessor
@Component
public class MysqlBeanPostProcessor implements BeanPostProcessor {

    public MysqlBeanPostProcessor() {
        System.out.println("=======run  MysqlBeanPostProcessor 构造函数====");
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof BeanA) {
            // 这里我们可以对bean 做一下扩展
            System.out.println("=====before Initialization  运行");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof BeanA) {
            System.out.println("=====after  Initialization  运行");
        }
        return bean;
    }
}
  1. 弄个启动类 运行一下
@SpringBootApplication
public class ApplicationMain {
    public static void main(String[] args) {
        SpringApplication.run(ApplicationMain.class, args);
    }
}
  1. 运行结果:
    1.可以看到 是先注入我们自定义的MysqlBeanPostProcessor ,然后作用于每一个Bean
  2. 先在Bean 实例之后,然后先运行before ,再运行 after 方法.(这个不够明朗,弄一下下面一个例子)
=======run  MysqlBeanPostProcessor 构造函数====
INFO 3360 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
INFO 3360 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
INFO 3360 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.19]
INFO 3360 --- [           main] o.a.catalina.core.AprLifecycleListener   : Loaded APR based Apache Tomcat Native library [1.2.23] using APR version [1.7.0].
INFO 3360 --- [           main] o.a.catalina.core.AprLifecycleListener   : APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].
INFO 3360 --- [           main] o.a.catalina.core.AprLifecycleListener   : APR/OpenSSL configuration: useAprConnector [false], useOpenSSL [true]
INFO 3360 --- [           main] o.a.catalina.core.AprLifecycleListener   : OpenSSL successfully initialized [OpenSSL 1.1.1c  28 May 2019]
INFO 3360 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
INFO 3360 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1135 ms
=======Bean A  构造函数======
=====before Initialization  运行
=====after  Initialization  运行

2.2 demo 增加 InitializingBean

将上面的BeanA 方法 实现一下 InitializingBean

@Configuration
public class BeanA implements InitializingBean {
    private static final Logger log = LoggerFactory.getLogger(BeanA.class);

    public BeanA() {
        System.out.println("=======Bean A  构造函数======");
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("=======Bean A  运行 InitializingBean 的 afterPropertiesSet======");
    }

}

运行结果:

=======run  MysqlBeanPostProcessor 构造函数====
INFO 4200 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
INFO 4200 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
INFO 4200 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.19]
INFO 4200 --- [           main] o.a.catalina.core.AprLifecycleListener   : Loaded APR based Apache Tomcat Native library [1.2.23] using APR version [1.7.0].
INFO 4200 --- [           main] o.a.catalina.core.AprLifecycleListener   : APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].
INFO 4200 --- [           main] o.a.catalina.core.AprLifecycleListener   : APR/OpenSSL configuration: useAprConnector [false], useOpenSSL [true]
INFO 4200 --- [           main] o.a.catalina.core.AprLifecycleListener   : OpenSSL successfully initialized [OpenSSL 1.1.1c  28 May 2019]
INFO 4200 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
INFO 4200 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1093 ms
=======Bean A  构造函数======
=====before Initialization  运行
=======Bean A  运行 InitializingBean 的 afterPropertiesSet======
=====after  Initialization  运行

2.3 demo 增加 @PostConstruct

修改 BeanA 代码如下:

@Configuration
public class BeanA implements InitializingBean {
    private static final Logger log = LoggerFactory.getLogger(BeanA.class);

    public BeanA() {
        System.out.println("=======Bean A  构造函数======");
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("=======Bean A  运行 InitializingBean 的 afterPropertiesSet======");
    }

    @PostConstruct
    public void init(){
        System.out.println("=======Bean A  运行 PostConstruct 的 初始化======");
    }
}

运行结果如下:
说明 beforxxx 、 afterxxx、 方法是在 @PostConstruct 前后运行

=======run  MysqlBeanPostProcessor 构造函数====
INFO 22072 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
INFO 22072 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
INFO 22072 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.19]
INFO 22072 --- [           main] o.a.catalina.core.AprLifecycleListener   : Loaded APR based Apache Tomcat Native library [1.2.23] using APR version [1.7.0].
INFO 22072 --- [           main] o.a.catalina.core.AprLifecycleListener   : APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].
INFO 22072 --- [           main] o.a.catalina.core.AprLifecycleListener   : APR/OpenSSL configuration: useAprConnector [false], useOpenSSL [true]
INFO 22072 --- [           main] o.a.catalina.core.AprLifecycleListener   : OpenSSL successfully initialized [OpenSSL 1.1.1c  28 May 2019]
INFO 22072 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
INFO 22072 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1325 ms
=======Bean A  构造函数======
=====before Initialization  运行
=======Bean A  运行 PostConstruct 的 初始化======
=======Bean A  运行 InitializingBean 的 afterPropertiesSet======
=====after  Initialization  运行

3. 源码分析

3.1 运行时机

接下来我们 看一下如何运行的,以及分析一下源码,在 打印日志的地方 打个断点,Debug 一下,如下图:
从下面我们可以看到
在这里插入图片描述
我们从上面的左下面的框框里面可以看到 这里是在 运行refresh() 里面方法时触发的,refresh这块后续整理一下//TODO,本次我们就从 AbstractAutowireCapableBeanFactory 类的 initializeBean 方法 开始解析
在这里插入图片描述
这里的流程也很清晰,大致为:
1.首先判断 是否设置了SecurityManagers ,如果设置了,就进行相关的权限配置 和 Aware 的扩展
2. 如果没有 直接进行 Aware 的扩展 ,Aware 这块就是 对相关的Bean 额外的配置一些响应的属性 ,代码块如下//TODO 后续整理一下
3. 判断bean 是不是应用程序自己定义的,如果不是 ,那就 遍历 运行 BeanPostProcessors 的postProcessBeforeInitialization 方法 这里有一个 getBeanPostProcessors() 方法,里面是获取所有的 实现了BeanPostProcessors 接口的类,这里是如果获取到的呢,在何时放进去的呢,下面会提到.

上面说到 的 注解 @PostConstruct 是在这一步运行的 ,相当于 BeanPostProcessors 的Beforxxxx 方法
4. 运行 invokeInitMethods ,这里有两种 ,一种是 继承了 InitializingBean ,那就实现 对应的afterPropertiesSet() 方法,或者是自定义的 InitMethod ,通过反射 去调用 上面的InitializingBean 和 自定义的initMethod 是在这一步运行
5. 判断bean 是不是应用程序自己定义的,如果不是 ,那就 遍历 运行 BeanPostProcessors 的postProcessAfterInitialization @PreDestory是在这一步 完成

// 这里就是对Bean 进行属性的配置
	private void invokeAwareMethods(final String beanName, final Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof BeanNameAware) {
				((BeanNameAware) bean).setBeanName(beanName);
			}
			if (bean instanceof BeanClassLoaderAware) {
				ClassLoader bcl = getBeanClassLoader();
				if (bcl != null) {
					((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
				}
			}
			if (bean instanceof BeanFactoryAware) {
				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
			}
		}
	}

// 这里就是 遍历的去运行 BeanPostProcessors 的postProcessBeforeInitialization 方法
	@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;
	}

3.2 getBeanPostProcessors()

上面提到 getBeanPostProcessors()里面的值是何时放进去的,其实 是在 refresh() 方法里面的 registerBeanPostProcessors(beanFactory) 里面进行收集的.
在这里插入图片描述

支付宝微信
支付宝微信
如果有帮助记得打赏哦特别需要您的打赏哦
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring源码解析是指对Spring框架的源代码进行深入分析和解读的过程。Spring框架是一个开源的Java企业级应用程序框架,提供了高度灵活和可扩展的开发环境。 Spring框架的源代码解析涉及了众多的模块和组件,包括核心容器、AOP(面向切面编程)、数据访问、Web开发等。通过对这些模块和组件的源代码进行解析,我们可以更加深入地了解Spring框架的工作原理和设计思想。 Spring源码解析的好处在于,可以帮助我们更好地理解Spring框架的各种功能和特性,并且能够帮助开发人员更加高效地使用和定制Spring框架,解决实际项目开发中的问题。 在进行Spring源码解析时,我们可以关注一些关键的概念和类,比如BeanFactory、ApplicationContext、BeanPostProcessor、AOP代理等。这些核心类和概念是理解Spring框架工作机制的重要基础。 进行Spring源码解析时,我们可以使用一些常见的工具和方法,比如IDE(集成开发环境)的调试功能、查看和分析源代码的注释和文档、调试和运行项目的示例代码等。 通过Spring源码解析,我们可以学到很多有关软件开发的知识和经验,比如面向对象编程、设计模式、依赖注入、控制反转等。这些知识和经验对于我们提升自己的技术水平和解决实际项目中的问题都有很大的帮助。 总之,Spring源码解析是一项非常有价值的学习和研究工作,可以帮助我们更好地理解和应用Spring框架,提高自己的技术能力和软件开发水平。希望以上的回答能够满足您的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一直打铁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值