文章目录
上一篇介绍了加载bean的一种特殊方法,这篇我们就来聊一聊正常加载bean的方式。
还是分步走,忽略一些部分,聚焦到整体流程。
- 创建一个包装类型的bean
- 为稍后对Bean内部属性的处理做一些前置工作
- 为后续该bean的获取增加更多方案(给开发者一种自定义解决循环依赖的切入口)
- 对bean的属性进行刷新
- 初始化bean(应该说是对各个切入点的通知)
- 曝光实例处理
- 注册一些bean销毁后的流程
创建包装类型的Bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
这方法的内部代码非常长,而且对我来说有点晦涩。相比于其它部分,它显得并不是那么重要。
这里我就简单总结总结一下,有兴趣的同学可以自行研究一下。
- 如果设置了
BeanDefinition
中的supplier属性,则通过supplier.get()方法获取BeanWrapper。 - 如果设置了
BeanDefinition
中的factoryMethodName,这通过另一种方式获取。(这里并没有深入研究) - 如果有默认构造器,则通过默认构造器创建实例。(这个应该是最简单的)
- 如果有构造器,则通过构造器创建(参数进行匹配,这里也没有深入研究)
Bean的前置处理
找到所有实现了MergedBeanDefinitionPostProcessor
的实例 ,然后访问其postProcessMergedBeanDefinition()
方法。
这里主要是为了后面填充Bean属性做一些前置准备。
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
//列举2个有感觉的
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
比如说 @Autowrited
,@Value
, @Resource
, @Lazy
等的前置处理工作就是在这个节点上触发的。
是否提前曝光
这一步主要是处理循环依赖,同时也为我们提供了一个解决方案的切入口。
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//添加循环依赖的解决方案
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
这个getEarlyBeanReference()
方法的触发节点就在最最上面,我们通过getSingloten()
获取单例的时候,如果从beanFactory中没有找到,那么就会通过实现了SmartInstantiationAwareBeanPostProcessor
接口实例的getEarlyBeanReference()
方法中获得。
填充属性(populateBean)
- 判断该bean是否进行属性填充。
- 访问各个处理器获取PropertyValues(实际上有些处理器直接进行了属性填充)。
- 根据返回的PropertyValues进行填充。
从这里可以看到BeanDefinition中的属性填充优先级是最高的,其次是个各个处理器。
第一步:判断该bean是否进行属性填充
//判断bean是否需要创建
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//如果返回false则跳过属性填充逻辑
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
主要是寻找所有实现了InstantiationAwareBeanPostProcessor
的实例,并访问其postProcessAfterInstantiation()
方法,如果返回的是false这跳过属性填充逻辑。
第二步:访问各个处理器获取PropertyValues(但有些处理器直接进行了填充)
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
这里其实按照思路来看应该是通过InstantiationAwareBeanPostProcessor
实例的 postProcessProperties()
方法 或 postProcessPropertyValues()
方法来获取PropertyValues 为后续的填充属性做准备。
但是,我在往里面继续查看的时候发现了很多处理器都是通过前置的反射直接对bean的属性进行赋值。 这个是个疑问点吧。感兴趣的同学可以自行研究一下,如果你有什么好想法,欢迎私信我 或在下方留言。
第三步:根据返回的PropertyValues进行填充
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
内部逻辑就不详细聊了。需要注意的是,它的填充方式是通过访问属性set方法,所以需要你保证必须有属性对应的set方法才行。(难道就是因为这个局限性?上面的处理方式是通过反射)
到此填充属性就完毕了。
初始化Bean
通过名字翻译过来确实是初始化bean,但给我的感觉它更像是,完结的通知,触发一个个的扩展节点。
因为在上面Bean已经实例化了,并且属性也注入完毕了,剩下的可不就只剩通知扩展节点了嘛。
我将它理解为4类通知,分别是:
- 特殊通知
- 前置通知
- 初始化通知
- 后置通知
特殊通知
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);
}
}
}
包含了三种,BeanNameAware
,BeanClassLoaderAware
,BeanFactoryAware
。
BeanNameAware
:创建完毕的Bean 名称通知
BeanClassLoaderAware
:加载Bean的classLoader 通知
BeanFactoryAware
:加载Bean的BeanFactory 通知
前置通知
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;
}
包含了一种,实现了BeanPostProcessor
实例的postProcessBeforeInitialization()
方法
其中又包含一个特例,如果有同学了解过Bean初始化的几种手段的话,应该知道一个注解@PostConstruct
这种初始化的手段是在前置通知中完成的。实现类是CommonAnnotationBeanPostProcessor
初始化通知
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
//第一种
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))){
((InitializingBean) bean).afterPropertiesSet()
}
}
//第二种
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
invokeCustomInitMethod(beanName, bean, mbd);
}
初始化通知包含两种
- 实现了
InitializingBean
接口 - 在BeanDefition中定义了初始方法的名称
initMethodName
后置通知
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;
}
包含一种,实现了BeanPostProcessor
实例的 postProcessAfterInitialization()
方法。
曝光实例处理
这里存在很多限制,也会引发一些问题。具体详情我将另开一章单独讲解。
注册一些Bean销毁后需要处理的实例
其实就是看下bean是否实现了DisposableBean接口,如果有,等bean销毁的时候调用其方法。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/121868.html