之前咱们曾经剖析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 公布!
发表回复