BeanPostProcessor注册与Bean生命周期过程

微信公众号原文链接:https://mp.weixin.qq.com/s/QUsaYbwDVQhMIFfy9DFeDAhttps://mp.weixin.qq.com/s/QUsaYbwDVQhMIFfy9DFeDA

疑问

后置处理器有什么作用?
BeanPostProcessor是什么时候被加载到Spring容器中的?
BeanPostProcessor保存在什么地方?
什么时候调用BeanPostProcessor的postProcessBeforeInitialization方法?
什么时候调用BeanPostProcessor的postProcessAfterInitialization方法?
本文将带着上述5个问题对Spring的后置处理器进行揭秘

SpringBoot启动流程简述

SpringBoot在启动过程中,首先会对创建Spring应用上下文ApplicationContext,并为其准备环境变量Environment,然后会扫描包下面的所有bean,并对bean进行解析验证,验证通过后会将bean加载到Spring容器中,加载完成后会对所有的bean进行初始化(即完成bean的生命周期),在进行其生命周期的过程中就会调用BeanPostProcessor相关的方法,对bean进行包装,如设置bean的属性值等;在初始化bean之前,就会将对应的后置处理器加载到Spring容器中。

SpringBoot注册BeanPostProcessor

在Spring组件开发过程中经常会使用到BeanPostProcessor接口,一个类实现了BeanPostProcessor接口,这个类就是一个后置处理器,而后置处理器的作用就是可以对bean进行代理及包装。下面将介绍BeanPostProcessor的注册过程
在AbstractApplicationContext类的下述方法中会对BeanPostProcessor进行注册

registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory)
然后Spring会委托注册后置处理器的代理类PostProcessorRegistrationDelegate来注册BeanPostProcessor

public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
//从Spring容器beanFactory中找到所有实现了BeanPostProcessor接口的类名称
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
//省略其余代码...
//通过类名称来创建具体的后置处理器 此处为伪代码 Spring中会将BeanPostProcessor分为多种类型的BeanPostProcessor接口
List<BeanPostProcessor> postProcessors = new ArrayList<>();
for (String ppName : postProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
postProcessors.add(pp);
}
//获取到的后置处理器实例后,将其注册到beanFactory中
registerBeanPostProcessors(beanFactory, postProcessors);
//省略其余代码...
}
接着会遍历List数组

private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {

for (BeanPostProcessor postProcessor : postProcessors) {
    beanFactory.addBeanPostProcessor(postProcessor)
}

}
将后置处理器保存到AbstractBeanFactory类的下述属性中,在后续的初始化bean生命周期过程中会遍历所有后置处理,调用其postProcessBeforeInitialization和postProcessAfterInitialization方法

/** BeanPostProcessors to apply in createBean */
private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();

@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
this.beanPostProcessors.remove(beanPostProcessor);
//保存后置处理器
this.beanPostProcessors.add(beanPostProcessor);
}
Bean生命周期过程

后置处理器的调用就在bean的生命周期中完成,可参考BeanFactory接口类上的注释,了解bean的整个生命周期过程

在spring启动过程中,会有很多次调用getBean方法来创建或获取bean实例

@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}

@Override
public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}

@Override
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, null, args, false);
}
如果spring容器没有创建好名称为name的bean,就会先去调用下述方法去创建这个bean

AbstractAutowireCapableBeanFactory.createBean()
创建bean的过程中会先通过下述方法进行属性填充

populateBean(beanName, mbd, instanceWrapper)
填充完成以后,接着去调用下述方法初始化bean

AbstractAutowireCapableBeanFactory.initializeBean(beanName, exposedObject, mbd)
初始化bean的过程就是bean的生命周期执行过程,而后置处理器BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法调用就在此过程中完成

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
//省略部分代码...
//调用Aware接口的setXXX方法
invokeAwareMethods(beanName, bean);

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
    //调用BeanPostProcessor接口的BeanPostProcessorsBeforeInitialization方法
    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
    //调用自定义的init-method方法
    invokeInitMethods(beanName, wrappedBean, mbd);
}catch (Throwable ex) {
    throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
    //调用BeanPostProcessor接口的postProcessAfterInitialization方法
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;

}
执行invokeAwareMethods时,会判断当前bean是否实现XXXAware接口,如果实现了XXXAware接口,则会去调用setXXX方法

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);
}
}
}
执行applyBeanPostProcessorsBeforeInitialization方法,会遍历Spring容器中所有的后置处理器,而且会调用每个后置处理器的postProcessBeforeInitialization方法

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
执行invokeInitMethods方法,会先判断当前的bean有没有实现InitializingBean接口,如果实现了,则会调用InitializingBean接口的afterPropertiesSet()方法,然后判断是否自定义了init-method,如果有,则会执行其init-method

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
//省略部分代码
//调用afterPropertiesSet方法
((InitializingBean) bean).afterPropertiesSet();

//判断如果自定义了init-method,就会执行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);
    }
}

}
最后执行applyBeanPostProcessorsAfterInitialization方法,会遍历Spring容器中所有的后置处理器,而且会调用每个后置处理器的postProcessAfterInitialization方法

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {

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

}
通过bean的生命周期执行过程,就可了解BeanPostProcessor的整个调用过程

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容