BeanPostProcessor原理案例解释——通过实现ApplicationContextAware实现向bean中注册ioc容器

首先指出确实是为了增强个人理解整理,语言可能过于粗糙。跟着视频整理所得。

**

首先从代码层面看一下BeanPostProcessor的简单原理过程。

**
(1)debug运行,跟踪debug中方法栈,一直走到protected Object doCreateBean(…)中:该方法中和关键代码如下:

在这里插入图片描述

(2)可以看到populateBean(beanName, mbd, instanceWrapper)方法在initializeBean(beanName, exposedObject, mbd)方法之前,这个方法作用是处理属性赋值。

**(3)核心就是initializeBean(beanName, exposedObject, mbd)这个方法:**进入查看:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nbigtwaz-1590222480656)(E:\MarkDown\8.spring基于注解开发\images\img6.png)]

  • 可以看到invokeInitMethods(beanName, wrappedBean, mbd)为初始化方法。
  • 而applyBeanPostProcessorsBeforeInitializatio()方法就是在初始化方法之前调用
  • applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);方法在初始化方法中调用

(4)打开applyBeanPostProcessorsBeforeInitializatio()方法,

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

		Object result = existingBean;
		for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
			result = beanProcessor.postProcessBeforeInitialization(result, beanName);
			if (result == null) {
				return result;
			}
		}
		return result;
	}

可以看到,它遍历了所有的后置处理器,一旦处理器为空,就直接结束该方法调用。

案例解释BeanPostProcessor应用

通过实现ApplicationContextAware实现向bean中注册ioc容器,完成特定功能。

底层使用的是这个ApplicationContextAwareProcessor,实现了BeanPostProcessor处理器。

首先bean类需要实现ApplicationContextAware接口,重写setApplicationContext方法。

@Component
public class Dog implements ApplicationContextAware {
	
	//以set方式注入到spring上下文获得容器
	private ApplicationContext applicationContext;
	
	public Dog(){
		System.out.println("dog constructor...");
	}
	
	//对象创建并赋值之后调用
	@PostConstruct
	public void init(){
		System.out.println("Dog....@PostConstruct...");
	}
	
	//容器移除对象之前
	@PreDestroy
	public void detory(){
		System.out.println("Dog....@PreDestroy...");
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		System.out.println("-------设置applicationContext-----------");
		this.applicationContext = applicationContext;
	}

}

先来看运行结果:

Dog类构造器…
-------设置applicationContext-----------
postProcessBeforeInitialization…dog=>org.jcut.bean.Dog@76a4d6c
Dog初始化方法…通过@PostConstruct注解实现
postProcessAfterInitialization…dog=>org.jcut.bean.Dog@76a4d6c

可以看到自定义MyBeanPostProcessor中方法是在初始化前后执行的。但是在这里不要被误导,我们要说的是“-------设置applicationContext-----------”这一行的内容,它底层是如何通过ApplicationContextAwareProcessor这个处理器完成注入上下文环境的。

核心源码解读:

(1)进入debug,进入到这个栈方法中:

DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).doCreateBean(String, RootBeanDefinition, Object[])

populateBean(beanName, mbd, instanceWrapper);
		if (exposedObject != null) {
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}

可以看到populateBean(beanName, mbd, instanceWrapper);这个方法其实就是进行一些属性赋值,调用构造器生成bean对象。

而处理器bean的核心方法就是 initializeBean(beanName, exposedObject, mbd);方法

(2)进入DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).initializeBean(String, Object, RootBeanDefinition)

if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, 		beanName);
		}
		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}

可以看到,它先执行了一个applyBeanPostProcessorsBeforeInitialization(wrappedBean, eanName);方法,而这个方法就是所有后处理bean的一个前置方法的调用。简单点说,就是假如你有多个Processor,分别实现了前值方法和后置方法,那么这些所有的前值方法都会在applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);中调用,我们进去看一下:

(3)进入DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).applyBeanPostProcessorsBeforeInitialization(Object, String)方法中.

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

		Object result = existingBean;
       //注意这里
		for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
			result = beanProcessor.postProcessBeforeInitialization(result, beanName);
			if (result == null) {
				return result;
			}
		}
		return result;
	}

(4)进入后,会得到这个bean所关联的所有beanProcessor,调用每个处理器的前置方法。其实这里会得到很多beanProcessor,我们这里只以两个处理器bean来说明,分别是我们自定义的MyBeanPostProcessor和ApplicationContextAwareProcessor分析,它首先会调用ApplicationContextAwareProcessor类的postProcessBeforeInitialization()方法,进入查看,

public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
		//只留这个方法说明问题,调用了这个方法
			invokeAwareInterfaces(bean);
		return bean;
	}

(5)又调用了一下方法:

private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof EnvironmentAware) {
				((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
			}
			if (bean instanceof EmbeddedValueResolverAware) {
				((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
			}
			if (bean instanceof ResourceLoaderAware) {
				((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
			}
			if (bean instanceof ApplicationEventPublisherAware) {
				((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
			}
			if (bean instanceof MessageSourceAware) {
				((MessageSourceAware) bean).setMessageSource(this.applicationContext);
			}
            //看这里
			if (bean instanceof ApplicationContextAware) {
				((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
			}
		}
	}

可以看到,bean满足的是最后一个if语句。bean此时就是Dog的实例。核心也就是这句:

((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);这里它就会调用我们重写的方法。

//我们重写的方法
@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		System.out.println("-------设置applicationContext-----------");
		this.applicationContext = applicationContext;
	}

这样就把spring上下文注册进来,可以扩展我们的其他功能了。

补充:

再来看一下执行结果:
首先自定义的MyBeanPostProcessor 类如下:

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		// TODO Auto-generated method stub
		System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		// TODO Auto-generated method stub
		System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);
		return bean;
	}

}

看运行结果:

Dog类构造器…
-------设置applicationContext-----------
postProcessBeforeInitialization…dog=>org.jcut.bean.Dog@76a4d6c
Dog初始化方法…通过@PostConstruct注解实现
postProcessAfterInitialization…dog=>org.jcut.bean.Dog@76a4d6c

可以看到“-------设置applicationContext-----------”打印以后接下来打印的是:postProcessBeforeInitialization…dog=>org.jcut.bean.Dog@76a4d6c,说明第一个beanProcessor的前置方法(也就是setApplicationContext)执行完以后,继续执行了我们自定义的MyBeanPostProcessor的前置方法,这也解释了上面(3)中说明的循环调用的说法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值