之前咱们曾经剖析 SpringBoot 在 run 办法时,它会执行的 refresh() 容器的操作。
在 SpringBoot 中,refresh() 有十几个办法,每个办法的大重要水平是不一样的,咱们通过抓大放小的形式,剖析解决上图 3 个外围逻辑。
并且曾经钻研完了 invokeBeanFactoryPostProcessors 和 onRefresh 的逻辑,剖析它们的原理和设计思维。
之前次要剖析的:
原理有对 SpringBoot 的主动拆卸配置如何做到的、第三方技术如何进行扩大的、tomcat 如何启动的
设计思维有 SpringBoot 扩大接口设计、有对 Tomcat 组件的扩大设计、Spring 容器形象思维的设计、SpringBoot 和第三方技术整合的扩大设计等等。
refresh() 还有一个十分要害的操作,就是 bean 的实例化, 明天咱们就来看下 refresh 最初一个办法—finishBeanFactoryInitialization。
看看它如何执行 Bean 实例化的流程和设计的。
finishBeanFactoryInitialization 之前和之后的操作详情
能够看到,bean 的实例化前后,还是做了一些事件的, 次要执行的是一些扩大点,比方 listener 的扩大点执行、LifycycleProcessor 的执行。
这一节咱们外围关系的是 bean 创立流程和设计,所以咱们抓大放小,过就能够。间接来看上面创立 bean 吧。
preInstantiateSingletons 办法的外围脉络
其实 bean 的实例化大家或多或少都晓得一些。所以我不会特地具体的每一个办法都带大家看。
咱们还是本着先脉络后细节,最初思考的思维来剖析 Bean 的实例化,当你用这种办法剖析玩后,和你之前剖析对吧下有什么区别,能够感触下。
如果之后大家有诉求须要精读 Bean 实例化的逻辑,我之后能够思考放在 Spring 成长记中为大家认真带来 Bean 实例化的剖析。
这里咱们次要过下它的外围源码就能够了。
因为 SpringBoot 是为了更好的应用 Spring,它是基于 Spring 的。如果你懂 Spring 实例化,这块其实十分好了解的。
让咱们来看下吧!
finishBeanFactoryInitialization 次要的代码如下所示:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();}
这个办法的脉络其实比较清楚,其实最要害的只有一句话:
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
其余的都是给 beanFactory 补充点货色而已,不是很要害。
这句话从正文很分明的说了,是依据 BeanDefinition 实例化所有残余的单例非提早初始化的 bean。
整个办法我通过先脉络的思维,给大家概括了下:
public void preInstantiateSingletons() throws BeansException {List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 遍历所有 beanDefinition,基于 beanDefinition 创立 bean
for (String beanName : beanNames) {RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (isFactoryBean(beanName)) {
// 做一些解决 FactoryBean
// 再从容器中获取 bean,如果不存在就创立
getBean(beanName);
}else{
// 从容器中获取 bean,如果不存在就创立
getBean(beanName);
}
}
// 执行 Bean 的扩大操作
for (String beanName : beanNames) {Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {smartSingleton.afterSingletonsInstantiated();
}
}
}
下面的代码是我对源码精简后的逻辑,它的脉络十分清晰了整体如下图所示:
创立 bean 的外围流程
当你晓得了 preInstantiateSingletons 办法的外围脉络后,它次要触发的是 getBean 办法,之后触发了 doGetBean。
doGetBean 整个办法还是比较复杂的,我还是通过先脉络的思维,抓大放小后,给大家精简了下源码,精简后如下:
@Overrid
public Object getBean(String name) throws BeansException {return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {final String beanName = transformedBeanName(name);
Object bean;
// 尝试获取 bean,如果容器中有了,就不须要创立了
Object bean = getSingleton(beanName);
if(bean == nul){
//getFromParentBeanfacotry 以后容器没有 bean 对应的单例对象,尝试从父容器获取,如果父容器为空,则不做解决
// 默认父容器空,这里略过
// 以后 bean 的依赖 dependsOn 解决,递归调用 getBean
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {getBean(dep);
}
// 单例还是多例的形式创立 bean
if (mbd.isSingleton()) {bean = createBean(beanName, mbd, args);
}else if (mbd.isPrototype()) {bean = createBean(beanName, mbd, args);
}else {String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
bean = createBean(beanName, mbd, args);
}
}
//bean 的扩大,应用转换器解决 bean
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
return (T) bean;
}
doGetBean 整体代码办法通过,抓大放小,剖析脉络后,其实曾经很清晰了。次要做了这么几件事:
1)getSingleton 从容器 Beanfactory 中的 map 属性,获取 bean,如果非空,间接就能够应用
2)如果容器中没有这个 bean,通过判断是否单例,来执行对应的创立 bean 办法 createBean
3)如果以后 bean 的依赖 dependsOn 解决,递归调用 getBean
4)最初执行了 bean 的扩大,应用转换器解决 bean
doGetBean 办法的大体脉络,基本上就是这四步,如下图所示:
真正创立 bean 的逻辑,到当初咱们还是没有看到,须要持续向下找。doGetBean 之后上面就会执行 createBean
同理咱们应用之前的办法持续梳理脉络、抓大放小失去如下代码:
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {、//Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {return bean;}
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
这里 createBean 其实次要执行了 resolveBeforeInstantiation 和 doCreateBean 办法。
1)resolveBeforeInstantiation 办法从注解上看,是给动静代理创立一个对象的机会,也就说,能够通过 BeanPostProcessor 应用动静代理对某些 bean 间接进行创立。这个十分有意思,也很要害,你想想是不是有的技术就是利用这里进行创立的呢?
2)如果不满足第一个条件,就会应用 doCreateBean 来创立 Bean
整个逻辑如下图所示:
这里终于找到了一种 bean 创立的形式了,之后应该还有其余形式,比方反射。咱们持续来看 doCreateBean。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = null;
// 创立 bean,bean 的实例化
if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//bean 属性的填充
populateBean(beanName, mbd, instanceWrapper);
//bean 扩大点的触发
initializeBean(beanName, exposedObject, mbd);
//bean 扩大点的增加
registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
}
整个 doCreateBean 办法,通过咱们之前的思路,一样精简完后,脉络也很分明。次要有:
1)创立 bean,bean 的实例化
2)bean 属性的解决
3)bean 扩大点的触发
4)bean 扩大点的增加
doCreateBean 的脉络如下图所示:
这里能够看到,除了之前动静代理的截胡,终于找到了 bean 实例化,创立 bean 的中央了。
其余对 bean 属性解决和扩大点,咱们先不看。重点钻研分明 bean 的创立再说。
createBeanInstance 同样被咱们抓大放小后的代码如下:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
//instanceSupplier 形式创立 bean
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);
}
//FactoryMethod 形式创立 bean
if (mbd.getFactoryMethodName() != null) {return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// 反射的形式创立 bean
if (resolved) {if (autowireNecessary) {return autowireConstructor(beanName, mbd, null, null);
}
else {return instantiateBean(beanName, mbd);
}
}
return instantiateBean(beanName, mbd);
}
你会发现有多种创立的 bean 的形式,并不是只有反射,形式次要有:
1)instanceSupplier 形式创立 bean
2)FactoryMethod 形式创立 bean
3)反射的形式创立 bean
那么再算上之前动静代理创立 bean、Factorybean 创立的 bean。一共曾经有 5 种能够创立 bean 的形式,然而个别咱们还都是通过反射创立的居多。
你可能没有见过其余的形式创立的 bean,然而我在一些技术中也见过一些,给大家分享下:
比方
Shiro 框架应用 Factorybean 创立的就比拟多
动静代理创立 bean、dubbo 就有很多这么创立的
FactoryMethod 创立的 bean,SpringBoot 主动拆卸的时候有时候会用到,之前 tomcat 启动的时候,TomcatServletWebServerFactory 是不是就用到了。
instanceSupplier 是 Spring5 之后才有的,目前我还没有见到啥框架用到过 ….
好了不论如何,最终你取得了如下的一张图,总结 bean 的创立形式:
到这里 bean 的创立的流程,咱们就大体剖析完了,因为咱们不是剖析 Spring,所以就不会再对这外面的每个细节进行剖析了。
之后有机会出 Spring 成长记的时候,我能够在带大家详细分析吧。
只是相熟 SpringBoot 中,Spring 实例化 bean 的流程理解到这里根本就能够了。
创立的 bean 整个流程能够总结下图的几步:
Bean 实例化的扩大点设计
最初咱们来看下 Bean 扩大设计吧,这个其实网上都有一大堆了,然而你肯定要留神,你得会辨别优劣的文章、提炼关键点,要对这些有本人的思考才行。
就像我当初给大家分享的,就是我对扩大点的思考。这个是我始终给大家强调的。
好了,我来简略说下,我对 Bean 的扩大点设计的思考和了解吧。
在 Spring 中,Bean 实例化的时候,有很多扩大点,这些扩大点其实还是很要害的。
比方:在 Spring 的生态系统中,很多技术都是通过 Bean 的扩大点来实现的。而且包含第三方的技术,比方 bytetcc 分布式事物框架的实现原理和 Bean 扩大点 BeanPostProcessor 就有很大的关系、大企业自研框架,能够实现自定义注解的解决、自定义配置文件的解决、给本人开发的 bean 设置属性等等。
那 Bean 的扩大点设计了哪些呢?我给大家花了一个图,根本就能详情常见的扩大点了,当然可能还有一些其余的扩大点,不论有多少个,它们都是扩大点,正当利用就好了,这个是要害。
Bean 实例化时,常见的扩大点的设计如图所示:
小结
如果你去看 Bean 的实例化的整个流程,其实其中的细节很简单的,如果在简单中找到关键点,是 SpringBoot 成长记以来,始终想要教给大家的。
最初通过对 Bean 实例化的剖析,让大家纯熟的利用了之前的学到的先脉络后细节、抓大放小、连蒙带猜、画外围组件图、流程图、看正文等思维和办法。
而且每看一阵子逻辑,要对它做出思考,思考它的设计,它的扩大、它的思维理念等等。
这个是罕用的一套方法论,可能不适宜所有场景,然而大多状况能够让你浏览源码或者钻研技术原理的时候,不那么不安,不会感觉它们太难,能够让你有方向、有办法。
明天的内容,其实没有什么要总结的,比拟重要的就是最初 bean 的扩大设计,我就不在反复了。
好了,咱们下一节再见!
本文由博客一文多发平台 OpenWrite 公布!