首先指出确实是为了增强个人理解整理,语言可能过于粗糙。跟着视频整理所得。
**
首先从代码层面看一下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)中说明的循环调用的说法。