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

目录

  • 1. 解释
  • 2. demo
    • 2.1 common Demo
    • 2.2 demo 增加 InitializingBean
    • 2.3 demo 增加 @PostConstruct
  • 3. 源码分析
    • 3.1 运行时机
    • 3.2 getBeanPostProcessors()

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 一下,如下图:
从下面我们可以看到
spring源码解析之---BeanPostProcessor解析_第1张图片
我们从上面的左下面的框框里面可以看到 这里是在 运行refresh() 里面方法时触发的,refresh这块后续整理一下//TODO,本次我们就从 AbstractAutowireCapableBeanFactory 类的 initializeBean 方法 开始解析
spring源码解析之---BeanPostProcessor解析_第2张图片
这里的流程也很清晰,大致为:
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) 里面进行收集的.
spring源码解析之---BeanPostProcessor解析_第3张图片

支付宝 微信
支付宝 微信
如果有帮助记得打赏哦 特别需要您的打赏哦

你可能感兴趣的:(spring,spring,java,PostProcessor)