两个问题
在开始探讨源码前,我们先思考两个问题:
1、在Spring中,什么是Bean?跟对象有什么区别?
通过new关键字,反射,克隆等手段创建出来的就是对象。在Spring中,Bean一定是一个对象,但是对象不一定是一个Bean,一个被创建出来的对象要变成一个Bean要经过很多复杂的工序,例如需要被我们的BeanPostProcessor处理,需要经过初始化,需要经过AOP(AOP本身也是由后置处理器完成的)等。
2、在创建对象前,Spring还做了其它什么事情吗?
我们还是回到流程图中,其中相关的步骤如下:
在前面的三篇文章中,我们已经分析到了第3-5步的源码,而如果你对Spring源码稍有了解的话,就是知道创建对象以及将对象变成一个Bean的过程发生在第3-11步骤中。中间的五步分别做了什么呢?
1、registerBeanPostProcessors
就像名字所说的那样,注册BeanPostProcessor,这段代码在Spring官网阅读(八)容器的扩展点(三)(BeanPostProcessor)已经分析过了,所以在本文就直接跳过了,如果你没有看过之前的文章也没有关系,你只需要知道,在这里Spring将所有的BeanPostProcessor注册到了容器中
2、initMessageSource
初始化容器中的messageSource,如果程序员没有提供,默认会创建一个org.springframework.context.support.DelegatingMessageSource,Spring官网阅读(十一)ApplicationContext详细介绍(上) 已经介绍过了。
3、initApplicationEventMulticaster
初始化事件分发器,如果程序员没有提供,那么默认创建一个org.springframework.context.event.ApplicationEventMulticaster,Spring官网阅读(十二)ApplicationContext详解(中)已经做过详细分析,不再赘述
4、onRefresh
留给子类复写扩展使用
5、registerListeners
注册事件监听器,就是将容器中所有实现了org.springframework.context.ApplicationListener接口的对象放入到监听器的集合中。
创建对象的源码分析
在完成了上面的一些准备工作后,Spring开始来创建Bean了,按照流程,首先被调用的就是finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory)方法,我们就以这个方法为入口,一步步跟踪源码,看看Spring中的Bean到底是怎么创建出来的,当然,本文主要关注的是创建对象的这个过程,对象变成Bean的流程我们在后续文章中再分析
1、finishBeanFactoryInitialization
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // 初始化一个ConversionService用于类型转换,这个ConversionService会在实例化对象的时候用到 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)); } // 添加一个StringValueResolver,用于处理占位符,可以看到,默认情况下就是使用环境中的属性值来替代占位符中的属性 if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); } // 创建所有的LoadTimeWeaverAware String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); for (String weaverAwareName : weaverAwareNames) { getBean(weaverAwareName); } // 静态织入完成后将临时的类加载器设置为null,所以除了创建LoadTimeWeaverAware时可能会用到临时类加载器,其余情况下都为空 beanFactory.setTempClassLoader(null); // 将所有的配置信息冻结 beanFactory.freezeConfiguration(); // 开始进行真正的创建 beanFactory.preInstantiateSingletons(); }
上面的方法最终调用了org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons来创建Bean。
其源码如下:
2、preInstantiateSingletons
public void preInstantiateSingletons() throws BeansException { // 所有bd的名称 List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // 遍历所有bd,一个个进行创建 for (String beanName : beanNames) { // 获取到指定名称对应的bd RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); // 对不是延迟加载的单例的Bean进行创建 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { // 判断是否是一个FactoryBean if (isFactoryBean(beanName)) { // 如果是一个factoryBean的话,先创建这个factoryBean,创建factoryBean时,需要在beanName前面拼接一个&符号 Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { final FactoryBean<?> factory = (FactoryBean<?>) bean; boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit, getAccessControlContext()); } else { // 判断是否是一个SmartFactoryBean,并且不是懒加载的,就意味着,在创建了这个factoryBean之后要立马调用它的getObject方法创建另外一个Bean isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } } else { // 不是factoryBean的话,我们直接创建就行了 getBean(beanName); } } } // 在创建了所有的Bean之后,遍历 for (String beanName : beanNames) { // 这一步其实是从缓存中获取对应的创建的Bean,这里获取到的必定是单例的 Object singletonInstance = getSingleton(beanName); // 判断是否是一个SmartInitializingSingleton,最典型的就是我们之前分析过的EventListenerMethodProcessor,在这一步完成了对已经创建好的Bean的解析,会判断其方法上是否有 @EventListener注解,会将这个注解标注的方法通过EventListenerFactory转换成一个事件监听器并添加到监听器的集合中 if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { smartSingleton.afterSingletonsInstantiated(); return null; }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } }
上面这段代码整体来说应该不难,不过它涉及到了一个点就是factoryBean,如果你对它不够了解的话,请参考我之前的一篇文章:Spring官网阅读(七)容器的扩展点(二)FactoryBean
3、doGetBean
从上面的代码分析中我们可以知道,Spring最终都会调用到getBean方法,而getBean并不是真正干活的,doGetBean才是。另外doGetBean可以分为两种情况
- 创建的是一个FactoryBean,此时实际传入的name = & + beanName
- 创建的是一个普通Bean,此时传入的name = beanName
其代码如下:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { // 前面我们说过了,传入的name可能时& + beanName这种形式,这里做的就是去除掉&,得到beanName final String beanName = transformedBeanName(name); Object bean; // 这个方法就很牛逼了,通过它解决了循环依赖的问题,不过目前我们只需要知道它是从单例池中获取已经创建的Bean即可,循环依赖后面我单独写一篇文章 // 方法作用:已经创建的Bean会被放到单例池中,这里就是从单例池中获取 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { // 如果直接从单例池中获取到了这个bean(sharedInstance),我们能直接返回吗? // 当然不能,因为获取到的Bean可能是一个factoryBean,如果我们传入的name是 & + beanName 这种形式的话,那是可以返回的,但是我们传入的更可能是一个beanName,那么这个时候Spring就还需要调用这个sharedInstance的getObject方法来创建真正被需要的Bean bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { // 在缓存中获取不到这个Bean // 原型下的循环依赖直接报错 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // 核心要义,找不到我们就从父容器中再找一次 BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { return (T) parentBeanFactory.getBean(nameToLookup, args); } else if (requiredType != null) { return parentBeanFactory.getBean(nameToLookup, requiredType); } else { return (T) parentBeanFactory.getBean(nameToLookup); } } // 如果不仅仅是为了类型推断,也就是代表我们要对进行实例化 // 那么就将bean标记为正在创建中,其实就是将这个beanName放入到alreadyCreated这个set集合中 if (!typeCheckOnly) { markBeanAsCreated(beanName); } try { final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // 检查合并后的bd是否是abstract,这个检查现在已经没有作用了,必定会通过 checkMergedBeanDefinition(mbd, beanName, args); // @DependsOn注解标注的当前这个Bean所依赖的bean名称的集合,就是说在创建当前这个Bean前,必须要先将其依赖的Bean先完成创建 String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { // 遍历所有申明的依赖 for (String dep : dependsOn) { // 如果这个bean所依赖的bean又依赖了当前这个bean,出现了循环依赖,直接报错 if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } // 注册bean跟其依赖的依赖关系,key为依赖,value为依赖所从属的bean registerDependentBean(dep, beanName); try { // 先创建其依赖的Bean getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } // 我们目前只分析单例的创建,单例看懂了,原型自然就懂了 if (mbd.isSingleton()) { // 这里再次调用了getSingleton方法,这里跟方法开头调用的getSingleton的区别在于,这个方法多传入了一个ObjectFactory类型的参数,这个ObjectFactory会返回一个Bean sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } // 省略原型跟域对象的相关代码 return (T) bean; }
配合注释看这段代码应该也不难吧,我们重点关注最后在调用的这段方法即可
4、getSingleton(beanName,ObjectFactory)
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); synchronized (this.singletonObjects) { // 从单例池中获取,这个地方肯定也获取不到 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { // 工厂已经在销毁阶段了,这个时候还在创建Bean的话,就直接抛出异常 if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } // 在单例创建前,记录一下正在创建的单例的名称,就是把beanName放入到singletonsCurrentlyInCreation这个set集合中去 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { // 这里调用了singletonFactory的getObject方法,对应的实现就是在doGetBean中的那一段lambda表达式 singletonObject = singletonFactory.getObject(); newSingleton = true; } // 省略异常处理 finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } // 在单例完成创建后,将beanName从singletonsCurrentlyInCreation中移除 // 标志着这个单例已经完成了创建 afterSingletonCreation(beanName); } if (newSingleton) { // 添加到单例池中 addSingleton(beanName, singletonObject); } } return singletonObject; } }
分析完上面这段代码,我们会发现,核心的创建Bean的逻辑就是在singletonFactory.getObject()这句代码中,而其实现就是在doGetBean方法中的那一段lambda表达式,如下:
实际就是通过createBean这个方法创建了一个Bean然后返回,createBean又干了什么呢?
5、createBean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { RootBeanDefinition mbdToUse = mbd; // 解析得到beanClass,为什么需要解析呢?如果是从XML中解析出来的标签属性肯定是个字符串嘛 // 所以这里需要加载类,得到Class对象 Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } // 对XML标签中定义的lookUp属性进行预处理,如果只能根据名字找到一个就标记为非重载的,这样在后续就不需要去推断到底是哪个方法了,对于@LookUp注解标注的方法是不需要在这里处理的,AutowiredAnnotationBeanPostProcessor会处理这个注解 try { mbdToUse.prepareMethodOverrides(); } // 省略异常处理... try { // 在实例化对象前,会经过后置处理器处理 // 这个后置处理器的提供了一个短路机制,就是可以提前结束整个Bean的生命周期,直接从这里返回一个Bean // 不过我们一般不会这么做,它的另外一个作用就是对AOP提供了支持,在这里会将一些不需要被代理的Bean进行标记,就本文而言,你可以暂时理解它没有起到任何作用 Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } } // 省略异常处理... try { // doXXX方法,真正干活的方法,doCreateBean,真正创建Bean的方法 Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isDebugEnabled()) { logger.debug("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } // 省略异常处理... }
6、doCreateBean
本文只探讨对象是怎么创建的,至于怎么从一个对象变成了Bean,在后面的文章我们再讨论,所以我们主要就关注下面这段代码
// 这个方法真正创建了Bean,创建一个Bean会经过 创建对象 > 依赖注入 > 初始化 这三个过程,在这个过程中,BeanPostPorcessor会穿插执行,本文主要探讨的是创建对象的过程,所以关于依赖注入及初始化我们暂时省略,在后续的文章中再继续研究 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { // 这行代码看起来就跟factoryBean相关,这是什么意思呢? // 在下文我会通过例子介绍下,你可以暂时理解为,这个地方返回的就是个null instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { // 这里真正的创建了对象 instanceWrapper = createBeanInstance(beanName, mbd, args); } // 省略依赖注入,初始化 }
这里我先分析下this.factoryBeanInstanceCache.remove(beanName)这行代码。这里需要说一句,我写的这个源码分析的系列非常的细节,之所以选择这样一个个扣细节是因为我自己在阅读源码过程中经常会被这些问题阻塞,那么借着这些文章将自己踩过的坑分享出来可以减少作为读者的你自己在阅读源码时的障碍,其次也能够提升自己阅读源码的能力。如果你对这些细节不感兴趣的话,可以直接跳过,能把握源码的主线即可。言归正传,我们回到这行代码this.factoryBeanInstanceCache.remove(beanName)。什么时候factoryBeanInstanceCache这个集合中会有值呢?这里我还是以示例代码来说明这个问题,示例代码如下:
public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class); } } // 没有做什么特殊的配置,就是扫描了需要的组件,测试时换成你自己的包名 @ComponentScan("com.dmz.source.instantiation") @Configuration public class Config { } // 这里申明了一个FactoryBean,并且通过@DependsOn注解申明了这个FactoryBean的创建要在orderService之后,主要目的是为了在DmzFactoryBean创建前让容器发生一次属性注入 @Component @DependsOn("orderService") public class DmzFactoryBean implements FactoryBean<DmzService> { @Override public DmzService getObject() throws Exception { return new DmzService(); } @Override public Class<?> getObjectType() { return DmzService.class; } } // 没有通过注解的方式将它放到容器中,而是通过上面的DmzFactoryBean来管理对应的Bean public class DmzService { } // OrderService中需要注入dmzService @Component public class OrderService { @Autowired DmzService dmzService; }
在这段代码中,因为我们明确的表示了DmzFactoryBean是依赖于orderService的,所以必定会先创建orderService再创建DmzFactoryBean,创建orderService的流程如下:
其中的属性注入阶段,我们需要细化,也可以画图如下:
为orderService进行属性注入可以分为这么几步
- 找到需要注入的注入点,也就是orderService中的dmzService字段
- 根据字段的类型以及名称去容器中查询符合要求的Bean
- 当遍历到一个FactroyBean时,为了确定其getObject方法返回的对象的类型需要创建这个FactroyBean(只会到对象级别),然后调用这个创建好的FactroyBean的getObjectType方法明确其类型并与注入点需要的类型比较,看是否是一个候选的Bean,在创建这个FactroyBean时就将其放入了factoryBeanInstanceCache中。
4.在确定了唯一的候选Bean之后,Spring就会对这个Bean进行创建,创建的过程又经过三个步骤
- 创建对象
- 属性注入
- 初始化
在创建对象时,因为此时factoryBeanInstanceCache已经缓存了这个Bean对应的对象,所以直接通过this.factoryBeanInstanceCache.remove(beanName)这行代码就返回了,避免了二次创建对象。
7、createBeanInstance
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { Class<?> beanClass = resolveBeanClass(mbd, beanName); // 省略异常 // 通过bd中提供的instanceSupplier来获取一个对象 // 正常bd中都不会有这个instanceSupplier属性,这里也是Spring提供的一个扩展点,但实际上不常用 Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); } // bd中提供了factoryMethodName属性,那么要使用工厂方法的方式来创建对象,工厂方法又会区分静态工厂方法跟实例工厂方法 if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } // 在原型模式下,如果已经创建过一次这个Bean了,那么就不需要再次推断构造函数了 boolean resolved = false; // 是否推断过构造函数 boolean autowireNecessary = false; // 构造函数是否需要进行注入 if (args == null) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { if (autowireNecessary) { return autowireConstructor(beanName, mbd, null, null); } else { return instantiateBean(beanName, mbd); } } // 推断构造函数 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // 调用无参构造函数创建对象 return instantiateBean(beanName, mbd); }
上面这段代码在Spring官网阅读(一)容器及实例化 已经分析过了,但是当时我们没有深究创建对象的细节,所以本文将详细探讨Spring中的这个对象到底是怎么创建出来的,这也是本文的主题。
在Spring官网阅读(一)容器及实例化 这篇文章中,我画了下面这么一张图