前言

通过往期的文章我们已经了解了Spring对XML配置文件的解析,将分析的信息组装成BeanDefinition,并将其保存到相应的BeanDefinitionRegistry中,至此Spring IOC的初始化工作已经完成,这篇文章主要对Bean的加载进行一个深入的了解及探索。

想要了解Bean就必要要知道接口BeanFactory,接下来我们就从BeanFactory切入

BeanFactory

我们在调用getBean()方法时,无论是显示调用还是隐式调用。都会触发Bean加载的阶段。demo如下:

  1. @Test
  2. public void Test(){
  3. //使用BeanFactory方式加载XML.
  4. BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
  5. MyTestBean myTestBean = (MyTestBean) beanFactory.getBean("myTestBean");
  6. System.out.println(myTestBean.getName());
  7. }

实际上这个getBean方法是在接口BeanFactory中定义的。我们先看一下BeanFactory的类图:

根据如上类图最一个简单的整理:

  • BeanFactory作为一个主接口不继承实现任何接口,我们可以定义为一级接口。

  • 有3个子接口都继承了它,进行功能上的增强,这3个子接口我们可以定义为二级接口。

  • ConfiguratbleBeanFactory我们可以定义为三级接口,对二级接口HierarchicalBeanFactory,进行再次增强。它还继承了另外一个接口SingletomBeanRegistry

  • ConfigurableListableBeanFactory是一个更强大的接口,继承了上述的所有接口,无所不包,我们可以定义为四级接口,(这4级接口是BeanFactory的基本接口体系,继续,下面是继承关系的2个抽象类和2个实现类)

  • AbstractBeanFactory作为一个抽象类,实现了三级接口ConfigurableBe·anFactory

  • AbstractAutowireCapableBeanFactory同样是抽象类继承自AbstractBeanFactory,并额外实现了二级接口AutowireCapableBeanFactory

  • DefaultListableBeanFactory继承自AbstractAutowireCapableBeanFactory实现了强大的四级接口ConfigurableListableBeanFactory,并实现了一个外来接口BeanDefinitionRegistry,它并非抽象类。

  • 最后就是强大的XmlBeanFactory继承自DefaultListableBeanFactory,重写了一些功能,是自己更强大。

BeanFactory,以Factory结尾,表示它是一个工厂类(接口),它负责生产和管理Bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。BeanFactory只是一个接口,并不是IOC的具体实现,但Spring容器给出了很多种实现,如:DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组件应用的对象及对象之间的依赖关系。XmlBeanFactory类将持有此Xml配置元数据,并用它来构建一个完全可配置的系统或应用。

BeanFactory是Spring IOC容器的鼻祖,是IOC容器的基础接口,所有的容器都是从它这里继承实现而来的。可以见其地位是多么重要。BeanFactory提供了最基本的IOC容器的功能,即所有的容器至少需要实现的标准。

XmlBeanFactory,只是提供了最基本的IOC容器的功能。而且XmlBeanFactory继承自DefaultListableBeanFactory。DefaultListableBeanFactory实际包含了基本IOC容器所具有的所有重要功能,是一个完整的IOC容器

ApplicationContext包含了BeanFactory的所有功能,通常建议比BeanFactory优先。

BeanFactory体系结构是典型的工厂方法模式,即什么样的工厂生产什么样的产品。BeanFactory是最基本的抽象工厂,而其它的IOC容器只不过是具体的工厂,对应着各自的Bean定义方法。但同时,其它容器也针对具体场景不同,进行了扩充,提供了具体的服务,如下:

  1. // 1
  2. Resource resource = new FileSystemResource("beans.xml");
  3. BeanFactory factory = new XmlBeanFactory(resource);
  4. // 2
  5. ClassPathResource resource = new ClassPathResource("beans.xml");
  6. BeanFactory factory = new XmlBeanFactory(resource);
  7. // 3
  8. ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"});
  9. BeanFactory factory = (BeanFactory) context;

大概就是这些了,接着使用getBean(String beanName)方法取得bean的实例;BeanFactory提供的方法极其简单,仅仅提供了六种方法供客户调用:

  • boolean containsBean(String name);判断工厂中是否包含了给定名称的Bean定义,若有则返回true
  • Object getBean(String name);返回给定名称注册的bean实例。根据Bean的配置情况,如果是singleton模式将返回一个共享的实例,否则将返回一个新建的实例,如果没有找到指定Bean,该方法会抛出异常(BeansException)。
  • < T> T getBean(String name, Class requiredType) ;返回给定名称注册的Bean实例,并转换为给定class类型。
  • boolean isSingleton(String name); 判断给定名称的Bean定义是否是单例模式。
  • Class<?> getType(String name); 返回给定名称的Bean的Class,如果没有找到指定的Bean实例,则抛出NoSuchBeanDefinitionException异常。
  • String[] getAliases(String name); 返回给定名称Bean的所有别名。

我们大致看一下BeanFactory源码里的所有方法。

  1. public interface BeanFactory {
  2. String FACTORY_BEAN_PREFIX = "&";
  3. Object getBean(String name) throws BeansException;
  4. <T> T getBean(String name, Class<T> requiredType) throws BeansException;
  5. Object getBean(String name, Object... args) throws BeansException;
  6. <T> T getBean(Class<T> requiredType) throws BeansException;
  7. <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
  8. <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
  9. <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
  10. Boolean containsBean(String name);
  11. Boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
  12. Boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
  13. Boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
  14. Boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
  15. @Nullable
  16. Class<?> getType(String name) throws NoSuchBeanDefinitionException;
  17. @Nullable
  18. Class<?> getType(String name, Boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
  19. String[] getAliases(String name);
  20. }

FactoryBean

概述:一一般情况下,Spring通过反射机制利用< bean>的class属性指定实现类实例化Bean,在某些情况下,实例化Bean的过程比较复杂,如果按照传统的方式,则需要在< bean>中提供大量的配置信息;配置方式的灵活性是受限的,这是采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.beans.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占有重要的地位,Spring自身就提供了70多个Factory Bean的实现,它们隐藏实例化一些复杂Bean的细节,给上层应用带来了便利,从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean< T>的形式。

以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它实现了FactoryBean< T> 接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身,如果想要获取FactoryBean对象,请在id前面加一个&符号来获取。

  • 看源码(FactoryBean.java)
  1. public interface FactoryBean<T> {
  2. String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
  3. @Nullable
  4. T getObject() throws Exception;
  5. @Nullable
  6. Class<?> getObjectType();
  7. default Boolean isSingleton() {
  8. return true;
  9. }
  10. }

从上述源码中我们可以看到,该接口一共定义了3个方法:

  • T getObject() throws Exception; 返回由FactoryBean创建的Bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单例实例缓存池中;
  • Class<?> getObjectType(); 返回FactoryBean创建的Bean实例;
  • default boolean isSingleton() { return true;} 返回FactoryBean创建的Bean实例的作用域是singleton还是prototype;

补充:当配置文件中< bean>的class属性配置的实现类是FactoryBean时,通过getBean()方法返回的不是FactoryBean本身,而是FactoryBean中的getObject()方法所返回的对象,相当于FactoryBean的getObject()代理了getBean()方法。

例如:如果使用传统方式配置下面的Car的< bean>时,Car的每个属性分别对应一个< property>元素标签。

  1. public class Car {
  2. private int maxSpeed ;
  3. private String brand ;
  4. private double price ;
  5. //get//set 方法
  6. }

如果使用FactoryBean的方式实现的话就比较灵活,下例通过逗号的分割的方式一次性为Car的所有属性指定配置值。

  1. import org.springframework.beans.factory.FactoryBean;
  2. public class CarFactoryBean implements FactoryBean<Car> {
  3. private String carInfo ;
  4. public Car getObject() throws Exception {
  5. Car car = new Car();
  6. String[] infos = carInfo.split(",");
  7. car.setBrand(infos[0]);
  8. car.setMaxSpeed(Integer.valueOf(infos[1]));
  9. car.setPrice(double.valueOf(infos[2]));
  10. return car;
  11. }
  12. public Class<Car> getObjectType(){
  13. return Car.class ;
  14. }
  15. public Boolean isSingleton(){
  16. return false ;
  17. }
  18. public String getCarInfo(){
  19. return this.carInfo;
  20. }
  21. //接受逗号分割符设置属性信息
  22. public void setCarInfo (String carInfo){
  23. this.carInfo = carInfo;
  24. }
  25. }

根据上述的CarFactoryBean,在配置文件中使用如下的方式进行配置

  1. <bean d="car"class="com.vipbbo.spring.CarFactoryBean" P:carInfo="大奔,600,1000000"/>

当调用getBean("car")时,Spring通过反射机制发现CarFactoryBean实现了FactoryBean的接口,这时Spring容器就调用接口方法CarFactoryBean的getObject()方法返回。如果希望获取CarFactoryBean的实例,则需要在使用getBean(BeanName)方法时在BeanName前面加上"&"前缀:比如:getBean("&car");

获取Bean

接下来我们继续回到文章一开始讲的bean的加载阶段,当我们显式或隐式调用getBean()时,则会触发加载Bean的阶段,具体实现如下:

  • 看源码(AbstractBeanFactory.java)
  1. @Override
  2. public Object getBean(String name) throws BeansException {
  3. return doGetBean(name, null, null, false);
  4. }

getBean()方法内部又调用了dogetBean()方法:

  • 看源码(AbstractBeanFactory.java)
  1. protected <T> T doGetBean(
  2. String name, @Nullable Class<T> requiredType, @Nullable Object[] args, Boolean typeCheckOnly)
  3. throws BeansException {
  4. // 获取 beanName,这里是一个转换动作,将 name 转换为 beanName
  5. String beanName = transformedBeanName(name);
  6. Object beanInstance;
  7. /*
  8. 检查缓存中的实例工程是否存在对应的bean实例。
  9. 为何要优先使用这段代码呢?
  10. 因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,Spring创建Bean的原则是在不等Bean创建完就会将
  11. 创建Bean的 objectFactory 提前曝光,即将其加入到缓存中,一旦下一个 Bean 创建时依赖上一个Bean则直接使用 objectFactory,直接
  12. 从缓存中或 singletonFactories 获取 objectFactory
  13. 就算没有循环依赖,只是单纯的依赖注入,如:B依赖A,如果A已经初始化完成,B进行初始化时,需要递归调用getBean()获取去A,这时A已经在
  14. 缓存里了,可以直接在这里获取到。
  15. */
  16. // Eagerly check singleton cache for manually registered singletons.
  17. Object sharedInstance = getSingleton(beanName);
  18. if (sharedInstance != null && args == null) {
  19. if (logger.isTraceEnabled()) {
  20. if (isSingletonCurrentlyInCreation(beanName)) {
  21. logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
  22. "' that is not fully initialized yet - a consequence of a circular reference");
  23. } else {
  24. logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
  25. }
  26. }
  27. // 返回对应的实例,有些时候并不是直接返回实例,而是返回某些方法返回的实例
  28. /*
  29. 这里涉及到我们上面讲的FactoryBean,如果此 Bean 是 FactoryBean 的实现类,如果name前缀为 "&",则直接返回此实现类的Bean,如果
  30. 没有前缀,则需要调用此实现类的getObject方法,返回getObject里真实的返回对象。
  31. */
  32. beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
  33. } else {
  34. // Fail if we're already creating this bean instance:
  35. // We're assumably within a circular reference.
  36. // 只有在单例的情况下才会解决循环依赖
  37. if (isPrototypeCurrentlyInCreation(beanName)) {
  38. throw new BeanCurrentlyInCreationException(beanName);
  39. }
  40. // Check if bean definition exists in this factory.
  41. // 尝试从 parentBeanFactory 中查找 bean
  42. BeanFactory parentBeanFactory = getParentBeanFactory();
  43. if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
  44. // Not found -> check parent.
  45. String nameToLookup = originalBeanName(name);
  46. if (parentBeanFactory instanceof AbstractBeanFactory) {
  47. return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
  48. nameToLookup, requiredType, args, typeCheckOnly);
  49. } else if (args != null) {
  50. // Delegation to parent with explicit args.
  51. return (T) parentBeanFactory.getBean(nameToLookup, args);
  52. } else if (requiredType != null) {
  53. // No args -> delegate to standard getBean method.
  54. return parentBeanFactory.getBean(nameToLookup, requiredType);
  55. } else {
  56. return (T) parentBeanFactory.getBean(nameToLookup);
  57. }
  58. }
  59. // 如果不是仅仅做类型检查,则这里需要创建bean,并做记录
  60. if (!typeCheckOnly) {
  61. markBeanAsCreated(beanName);
  62. }
  63. StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
  64. .tag("beanName", name);
  65. try {
  66. if (requiredType != null) {
  67. beanCreation.tag("beanType", requiredType::toString);
  68. }
  69. // 将存储XML配置文件的GenericBeanDefinition转换成RootBeanDefinition,同时如果存在父Bean合并父Bean的相关属性
  70. RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
  71. checkMergedBeanDefinition(mbd, beanName, args);
  72. // Guarantee initialization of beans that the current bean depends on.
  73. // 如果存在依赖,则需要递归实例化依赖的Bean
  74. String[] dependsOn = mbd.getDependsOn();
  75. if (dependsOn != null) {
  76. for (String dep : dependsOn) {
  77. if (isDependent(beanName, dep)) {
  78. throw new BeanCreationException(mbd.getResourceDescription(), beanName,
  79. "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
  80. }
  81. registerDependentBean(dep, beanName);
  82. try {
  83. getBean(dep);
  84. }
  85. catch (NoSuchBeanDefinitionException ex) {
  86. throw new BeanCreationException(mbd.getResourceDescription(), beanName,
  87. "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
  88. }
  89. }
  90. }
  91. // Create bean instance.
  92. // 单例模式的Bean
  93. if (mbd.isSingleton()) {
  94. // 实例化依赖的Bean后对Bean本身进行实例化
  95. sharedInstance = getSingleton(beanName, () -> {
  96. try {
  97. return createBean(beanName, mbd, args);
  98. }
  99. catch (BeansException ex) {
  100. // Explicitly remove instance from singleton cache: It might have been put there
  101. // eagerly by the creation process, to allow for circular reference resolution.
  102. // Also remove any beans that received a temporary reference to the bean.
  103. destroySingleton(beanName);
  104. throw ex;
  105. }
  106. }
  107. );
  108. beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
  109. }
  110. // 原型模式 else if (mbd.isPrototype()) {
  111. // It's a prototype -> create a new instance.
  112. Object prototypeInstance = null;
  113. try {
  114. beforePrototypeCreation(beanName);
  115. prototypeInstance = createBean(beanName, mbd, args);
  116. }
  117. finally {
  118. afterPrototypeCreation(beanName);
  119. }
  120. beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
  121. }
  122. // 从指定的 scope 模式下创建 Bean else {
  123. String scopeName = mbd.getScope();
  124. if (!StringUtils.hasLength(scopeName)) {
  125. throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
  126. }
  127. Scope scope = this.scopes.get(scopeName);
  128. if (scope == null) {
  129. throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
  130. }
  131. try {
  132. Object scopedInstance = scope.get(beanName, () -> {
  133. beforePrototypeCreation(beanName);
  134. try {
  135. return createBean(beanName, mbd, args);
  136. }
  137. finally {
  138. afterPrototypeCreation(beanName);
  139. }
  140. }
  141. );
  142. beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
  143. }
  144. catch (IllegalStateException ex) {
  145. throw new ScopeNotActiveException(beanName, scopeName, ex);
  146. }
  147. }
  148. }
  149. catch (BeansException ex) {
  150. beanCreation.tag("exception", ex.getClass().toString());
  151. beanCreation.tag("message", String.valueOf(ex.getMessage()));
  152. cleanupAfterBeanCreationFailure(beanName);
  153. throw ex;
  154. }
  155. finally {
  156. beanCreation.end();
  157. }
  158. }
  159. return adaptBeanInstance(name, beanInstance, requiredType);
  160. }
  1. @SuppressWarnings("unchecked")
  2. <T> T adaptBeanInstance(String name, Object bean, @Nullable Class<?> requiredType) {
  3. // Check if required type matches the type of the actual bean instance.
  4. if (requiredType != null && !requiredType.isInstance(bean)) {
  5. try {
  6. Object convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
  7. if (convertedBean == null) {
  8. throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
  9. }
  10. return (T) convertedBean;
  11. }
  12. catch (TypeMismatchException ex) {
  13. if (logger.isTraceEnabled()) {
  14. logger.trace("Failed to convert bean '" + name + "' to required type '" +
  15. ClassUtils.getQualifiedName(requiredType) + "'", ex);
  16. }
  17. throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
  18. }
  19. }
  20. return (T) bean;
  21. }

dogetBean()方法的源码时相当的长,一共包含了两部分,也可以说是一部分,接下来:进行拆分讲解:

1. 获取BeanName
  • 看源码(AbstractBeanFactory.java)
  1. // 获取 beanName,这里是一个转换动作,将 name 转换为 beanName
  2. String beanName = transformedBeanName(name);
  1. protected String transformedBeanName(String name) {
  2. return canonicalName(BeanFactoryUtils.transformedBeanName(name));
  3. }
  • 源码分析

这里要注意传递的name,不一定就是beanName,也有可能是aliasName 别名,也有可能是FactoryBean(带有”&“前缀),因此这里需要调用transformeBeanName()进行一下转换,主要内容如下:

  • 看源码(BeanFactoryUtils.java)
  1. public static String transformedBeanName(String name) {
  2. // 这个方法主要是去掉FactoryBean的修饰符 &
  3. Assert.notNull(name, "'name' must not be null");
  4. if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
  5. return name;
  6. }
  7. return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
  8. do {
  9. beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
  10. }
  11. while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
  12. return beanName;
  13. }
  14. );
  15. }

对aliasName别名的转换

  1. public String canonicalName(String name) {
  2. // 这个方法是转换aliasName
  3. String canonicalName = name;
  4. // Handle aliasing...
  5. String resolvedName;
  6. do {
  7. resolvedName = this.aliasMap.get(canonicalName);
  8. if (resolvedName != null) {
  9. canonicalName = resolvedName;
  10. }
  11. }
  12. while (resolvedName != null);
  13. return canonicalName;
  14. }
  • 源码分析

上述的处理过程大致可以分为两步:

  1. 去除FactoryBean的修饰符,如果name以"&"为前缀,那么会去掉"&",例如:name="&testService",去除之后的结果是name=”testService“
  2. 取出指定的alias所表示的最终的beanName,主要是一个循环beanName的过程,例如别名A指向名称为B的bean则返回B,若别名A指向别名B,别名B指向名称为C的bean,则返回C。
缓存中获取单例Bean

单例在Spring的同一个容器中只会被创建一次,后续再获取Bean直接从单例缓存中获取即可,当然这里也只是尝试加载,首先尝试先从缓存中加载,然后再次从singletonFactory加载;因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,Spring创建bean的原则是不等bean创建完成就会创建bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建时需要依赖上个bean,则直接使用ObejectFactory;就算没有循环依赖,只是单纯的依赖注入,如:B依赖A,如果A已经初始化完成,B进行初始化时,需要递归调用getBean()获取A,这时A已经在缓存里面了,直接可以从缓存里面获取到,接下来我们看获取单例bean的方法:

Object sharedInstance = getSingleton(beanName);

  • 看源码(DefaultSingletonBeanRegistry.java)
  1. @Override
  2. @Nullable
  3. public Object getSingleton(String beanName) {
  4. // 参数true,代表允许早期依赖
  5. return getSingleton(beanName, true);
  6. }
  1. @Nullable
  2. protected Object getSingleton(String beanName, Boolean allowEarlyReference) {
  3. // Quick check for existing instance without full singleton lock
  4. // 检查缓存中是否存在实例,这里就是说上面的单纯的依赖注入,假设B依赖A,如果A已经初始化完成,B进行初始化时,需要递归调用getBean获取A,这时
  5. // A已经在缓存里面了,直接可以从缓存中获取到。
  6. Object singletonObject = this.singletonObjects.get(beanName);
  7. // 如果缓存为空,且单例Bean正在创建中,则锁定全局变量,
  8. // 为什么要判断单例Bean是否在创建中呢?
  9. // 这里就是可以判断是否是循环依赖了。
  10. // A依赖B,B也依赖A,A实例化的时候发现依赖B,则递归去实例化B;B又发现依赖A,则递归实例化A。这个时候就会回到原点A的实例化,第一次A的
  11. // 实例化还没有完成,只不过是把实例化的对象加入到缓存中了,但是状态还是正在创建中。由此回到原点A发现A正在创建中,便可以根据此来判断这
  12. // 是循环依赖了
  13. if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
  14. // 尝试从 earlySingletonObjects 里面获取 如果此Bean正在加载,则不对其进行处理
  15. singletonObject = this.earlySingletonObjects.get(beanName);
  16. if (singletonObject == null && allowEarlyReference) {
  17. synchronized (this.singletonObjects) {
  18. // Consistent creation of early reference within full singleton lock
  19. // 尝试从singletonObjects里面获取实例
  20. singletonObject = this.singletonObjects.get(beanName);
  21. if (singletonObject == null) {
  22. // 当某些方法需要提前初始化的时候会直接调用 addSingletonFactory 把对应的 ObjectFactory 初始化策略 存储在
  23. // singletonFactories中。
  24. singletonObject = this.earlySingletonObjects.get(beanName);
  25. if (singletonObject == null) {
  26. ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
  27. if (singletonFactory != null) {
  28. // 使用预先设定的getObject方法
  29. singletonObject = singletonFactory.getObject();
  30. this.earlySingletonObjects.put(beanName, singletonObject);
  31. this.singletonFactories.remove(beanName);
  32. }
  33. }
  34. }
  35. }
  36. }
  37. }
  38. return singletonObject;
  39. }
  • 源码分析

我们对上述方法进行一个简单的梳理,

首先该方法先从singletonObjects里获取实例;

如果获取不到会从earlySingletonObjects里面获取实例;

如果还是获取不到,再次尝试从singletonFactories里面获取beanName对应的ObjectFactory,并从singletonFactories里面remove掉这个ObjectFactory,而对于后续所有的内存操作都只为了循环依赖检测时候使用,即allowEarlyReference为true时才会使用。

以上代码涉及到了很多个存储bean的不同Map:

singletonObjects:用于保存BeanName和创建Bean实例之间的关系,beanName->bean Instance

singletonFactories:用于保存BeanName和创建Bean的工厂之间的联系,beanName->ObjectFactory

earlySingletonObjects:同样也是用于保存BeanName和创建Bean实例之间的关系,与singletonObjects的不同之处在于:当一个单例bean被放到这里面后,那么当bean还在创建过程中,就可以通过getBean方法获取到了,其目的是用来检测循环依赖的引用。

registeredSingletons:用来保存当前所有已经注册的bean。

从bean的实例中获取对象

获取到bean以后就要获取实例对象了,这里用到的时getObjectForBeanInstance方法。getObjectForBeanInstance是一个频繁使用的方法,无论是从缓存中获取bean还是根据不同的scope策略加载Bean;总之,我们得到bean的实例后,要做的第一步就是调用这个方法来检测一下正确性,其实就是检测获得的Bean是不是FactoryBean类型的bean,

如果是那么需要调用该bean对应的FactoryBean实例中的getObject()作为返回值。

  • 看源码(AbstractBeanFactory.java)
  1. protected Object getObjectForBeanInstance(
  2. Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
  3. // Don't let calling code try to dereference the factory if the bean isn't a factory.
  4. // 如果指定的name 是工厂相关的
  5. if (BeanFactoryUtils.isFactoryDereference(name)) {
  6. // 如果是 NullBean 则直接返回此Bean
  7. if (beanInstance instanceof NullBean) {
  8. return beanInstance;
  9. }
  10. // 如果不是FactoryBean 类型,则直接抛出异常
  11. if (!(beanInstance instanceof FactoryBean)) {
  12. throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
  13. }
  14. if (mbd != null) {
  15. mbd.isFactoryBean = true;
  16. }
  17. return beanInstance;
  18. }
  19. // Now we have the bean instance, which may be a normal bean or a FactoryBean.
  20. // If it's a FactoryBean, we use it to create a bean instance, unless the
  21. // caller actually wants a reference to the factory.
  22. // 如果获取的beanInstance不是FactoryBean类型,说明是普通的Bean,可直接返回
  23. // 如果获取的beanInstance是FactoryBean 类型,但是是以&开头,也可直接返回,此时返回的是FactoryBean实例
  24. if (!(beanInstance instanceof FactoryBean)) {
  25. return beanInstance;
  26. }
  27. Object object = null;
  28. if (mbd != null) {
  29. mbd.isFactoryBean = true;
  30. } else {
  31. object = getCachedObjectForFactoryBean(beanName);
  32. }
  33. if (object == null) {
  34. // Return bean instance from factory.
  35. FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
  36. // Caches object obtained from FactoryBean if it is a singleton.
  37. if (mbd == null && containsBeanDefinition(beanName)) {
  38. mbd = getMergedLocalBeanDefinition(beanName);
  39. }
  40. Boolean synthetic = (mbd != null && mbd.isSynthetic());
  41. // 到这里说明了获取的beanInstance是FactoryBean类型的,但是没有以&开头,此时就要返回factory内部的getObject里面的对象了。
  42. // getObjectFromFactoryBean 核心方法
  43. object = getObjectFromFactoryBean(factory, beanName, !synthetic);
  44. }
  45. return object;
  46. }

接下来我们继续看一下里面的核心方法getObjectFromFactoryBean()

  • 看源码(FactoryBeanRegistrySupport.java)
  1. protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, Boolean shouldPostProcess) {
  2. // 满足是单例并且缓存中存在的
  3. if (factory.isSingleton() && containsSingleton(beanName)) {
  4. synchronized (getSingletonMutex()) {
  5. // 从缓存中获取FactoryBean根据BeanName
  6. Object object = this.factoryBeanObjectCache.get(beanName);
  7. if (object == null) {
  8. // 为空,则从FactoryBean中获取对象
  9. object = doGetObjectFromFactoryBean(factory, beanName);
  10. // Only post-process and store if not put there already during getObject() call above
  11. // (e.g. because of circular reference processing triggered by custom getBean calls)
  12. // 从缓存中获取
  13. Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
  14. if (alreadyThere != null) {
  15. object = alreadyThere;
  16. } else {
  17. // 需要后续处理
  18. if (shouldPostProcess) {
  19. // 若该 bean 处于创建中,则返回非处理对象,而不是存储它
  20. if (isSingletonCurrentlyInCreation(beanName)) {
  21. // Temporarily return non-post-processed object, not storing it yet..
  22. return object;
  23. }
  24. // 前置处理
  25. beforeSingletonCreation(beanName);
  26. try {
  27. // 对从 FactoryBean 获取的对象进行后处理
  28. // 生成的对象将暴露给bean引用
  29. object = postProcessObjectFromFactoryBean(object, beanName);
  30. }
  31. catch (Throwable ex) {
  32. throw new BeanCreationException(beanName,
  33. "Post-processing of FactoryBean's singleton object failed", ex);
  34. }
  35. finally {
  36. // 后置处理
  37. afterSingletonCreation(beanName);
  38. }
  39. }
  40. // 缓存
  41. if (containsSingleton(beanName)) {
  42. this.factoryBeanObjectCache.put(beanName, object);
  43. }
  44. }
  45. }
  46. return object;
  47. }
  48. }
  49. // 非单例 else {
  50. Object object = doGetObjectFromFactoryBean(factory, beanName);
  51. if (shouldPostProcess) {
  52. try {
  53. object = postProcessObjectFromFactoryBean(object, beanName);
  54. }
  55. catch (Throwable ex) {
  56. throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
  57. }
  58. }
  59. return object;
  60. }
  61. }
  • 源码分析

getObjectFromFactoryBean()该方法就是创建实例对象中的核心方法之一。我们关注它之中的单个方法即可:beforeSingletonCreationafterSingletonCreationpostProcessObjectFromFactoryBean,这三个方法十分重要,万分重要!!!!!!!!因为前两个方法记录着bean的加载状态,是检测当前bean是否处于创建中的关键之处,对解决bean循环依赖起着关键的作用。

before方法用于标记当前bean处于创建中,

after则是移除。

其实文章一开始的getSingleton源码分析就已经提到了isSingletonCurrentlyInCreation()是用于检测当前bean是否处于创建之中,

  • 看源码(DefaultSingletonBeanRegistry.java)
  1. public Boolean isSingletonCurrentlyInCreation(String beanName) {
  2. return this.singletonsCurrentlyInCreation.contains(beanName);
  3. }
beforeSingletonCreation()

上述代码是根据变量singletonsCurrentlyInCreation集合中是否包含了beanName判断,集合的元素则一定是在beforeSingletonCreation()中添加的,如下:

  1. protected void beforeSingletonCreation(String beanName) {
  2. if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
  3. throw new BeanCurrentlyInCreationException(beanName);
  4. }
  5. }
afterSingletonCreation

afterSingletonCreation()为移除,则一定就是对singletonsCurrentlyInCreation集合remove了,如下:

  1. protected void afterSingletonCreation(String beanName) {
  2. if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
  3. throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
  4. }
  5. }

接下来我们再来看看真正的核心方法 doGetObjectFromFactoryBean

  • 看源码(FactoryBeanRegistrySupport.java)
  1. private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
  2. Object object;
  3. try {
  4. if (System.getSecurityManager() != null) {
  5. AccessControlContext acc = getAccessControlContext();
  6. try {
  7. object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
  8. }
  9. catch (PrivilegedActionException pae) {
  10. throw pae.getException();
  11. }
  12. } else {
  13. object = factory.getObject();
  14. }
  15. }
  16. catch (FactoryBeanNotInitializedException ex) {
  17. throw new BeanCurrentlyInCreationException(beanName, ex.toString());
  18. }
  19. catch (Throwable ex) {
  20. throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
  21. }
  22. // Do not accept a null value for a FactoryBean that's not fully
  23. // initialized yet: Many FactoryBeans just return null then.
  24. if (object == null) {
  25. if (isSingletonCurrentlyInCreation(beanName)) {
  26. throw new BeanCurrentlyInCreationException(
  27. beanName, "FactoryBean which is currently in creation returned null from getObject");
  28. }
  29. object = new NullBean();
  30. }
  31. return object;
  32. }
  • 源码分析

在文章开始我们有介绍FactoryBean的调用方法,如果bean声明为FactoryBean类型,则当提取bean的是否提取的不是FactoryBean,而是FactoryBean中对应的getObject方法返回的bean,而doGetObjectRFromFactoryBean正是实现这一功能的。

调用完doGetObjectFromFactoryBean方法后,并没有直接返回,getObjectFromFactoryBean方法中还调用了object = postProcessObjectFromFactoryBean(object, beanName);方法,在子类AbstractAutowireCapableBeanFactory有该方法的具体实现:

  • 看源码(AbstractAutowireCapableBeanFactory.java)
  1. @Override
  2. protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
  3. return applyBeanPostProcessorsAfterInitialization(object, beanName);
  4. }
  1. @Override
  2. public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
  3. throws BeansException {
  4. Object result = existingBean;
  5. for (BeanPostProcessor processor : getBeanPostProcessors()) {
  6. Object current = processor.postProcessAfterInitialization(result, beanName);
  7. if (current == null) {
  8. return result;
  9. }
  10. result = current;
  11. }
  12. return result;
  13. }

对于后处理器的使用,目前还没有讲到,后面再重新开篇去说,这里我们只需要了解在Spring获取Bean的规则中有这样一条,尽可能保证所有bean初始化后都会调用注册的BeanPostProcessor的postProcessAfterInitialization方法进行处理,在实际开发中大可针对此特性设计自己的业务处理。

整理不易,如果对你有所帮助欢迎点赞关注

微信搜索【码上遇见你】获取更多精彩内容

一文带你解读Spring5源码解析 IOC之开启Bean的加载,以及FactoryBean和BeanFactory的区别。的更多相关文章

  1. spring源码深度解析— IOC 之 开启 bean 的加载

    概述 前面我们已经分析了spring对于xml配置文件的解析,将分析的信息组装成 BeanDefinition,并将其保存注册到相应的 BeanDefinitionRegistry 中.至此,Spri ...

  2. springboot源码解析-管中窥豹系列之BeanDefine如何加载(十三)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  3. Spring 源码学习(4)—— bean的加载part 1

    前面随笔中,结束了对配置文件的解析工作,以及将配置文件转换成对应的BeanDefinition存储在容器中.接下来就该进行bean的加载了. public Object getBean(String ...

  4. android源码解析(十七)-->Activity布局加载流程

    版权声明:本文为博主原创文章,未经博主允许不得转载. 好吧,终于要开始讲讲Activity的布局加载流程了,大家都知道在Android体系中Activity扮演了一个界面展示的角色,这也是它与andr ...

  5. Spring源码分析(十一)bean的加载

    摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 经过前面的分析,我们终于结束了对XML配置文件的解析,接下来将会面临更大 ...

  6. Spring源码学习(5)—— bean的加载 part 2

    之前归纳了从spring容器的缓存中直接获取bean的情况,接下来就需要从头开始bean的加载过程了.这里着重看单例的bean的加载 if(ex1.isSingleton()) { sharedIns ...

  7. Spring源码之IOC容器创建、BeanDefinition加载和注册和IOC容器依赖注入

    总结 在SpringApplication#createApplicationContext()执行时创建IOC容器,默认DefaultListableBeanFactory 在AbstractApp ...

  8. springboot源码解析-管中窥豹系列之bean如何生成?(十四)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  9. Spring5源码解析-Spring框架中的单例和原型bean

    Spring5源码解析-Spring框架中的单例和原型bean 最近一直有问我单例和原型bean的一些原理性问题,这里就开一篇来说说的 通过Spring中的依赖注入极大方便了我们的开发.在xml通过& ...

随机推荐

  1. 信不信由你!iPhone6屏幕宽度不一定是375px,iPhone6 Plus屏幕宽度不一定是414px

    看到这个题目你可能不信,引出这个问题的缘由是几次项目中Chrome模拟器和iPhone6真机预览效果不一致. 为什么在Chrome Emulation模拟手机页面和真机预览效果不一致? 以前觉得不外乎 ...

  2. boot项目打包剔除配置文件(打包优化)

    背景: 最近在项目开发中,在本地开发和线上部署的时候总是切换dev和pro环境,项目多了改起来还是很麻烦的,以下记录下boot项目的打包优化,打包的时候剔除配置文件,然后将配置文件手动放到线上,线上项 ...

  3. 【刷题-PAT】A1114 Family Property (25 分)

    1114 Family Property (25 分) This time, you are supposed to help us collect the data for family-owned ...

  4. Spring系列4:依赖注入的2种方式

    本文内容 基于构造器的依赖注入 基于setter的依赖注入 基于构造器的依赖注入 案例 定义2个简单的bean类,BeanOne 和 BeanTwo,前者依赖后者. package com.crab. ...

  5. openssl基本原理 + 生成证书(转)

    https://blog.csdn.net/cpcpcp123/article/details/108885922 https://liruzhen.blog.csdn.net/article/det ...

  6. 开发者的瑞士军刀「GitHub 热点速览 v.22.04」

    Swiss Army knife 可以说是本周的关键词了,多个项目采用该词来描述它的特性:像是能全方位解决浏览器"网络"操作的 CyberChef 方便你进行数据加密.解编码,还有 ...

  7. 挂载的卸载与运行 关闭selinux

    目录 一:系统目录结构介绍 1 定义挂载设备信息 光驱设备 /cd/cdrom 2 完成设备挂载操作 运行挂载 mount/dev/cdrom /mnt/ 3 检查测试挂载结果 挂载检查 df -h ...

  8. Nginx日志管理

    1 日志管理 1.1 Nginx日志描述 通过访问日志,你可以得到用户地域来源.跳转来源.使用终端.某个URL访问量等相关信息:通过错误日志,你可以得到系统某个服务或server的性能瓶颈等.因此,将 ...

  9. 常见线程池之 newCacheThreadPool 缓存线程池 简单使用

    package com.aaa.threaddemo; import java.util.concurrent.BlockingQueue; import java.util.concurrent.E ...

  10. SpringCloud整合Hystrix

    1.Hystrix简介 Hystrix是由Nefflix开源的一个延迟和容错库,用于隔离访问远程系统.服务或第三方库,防止级联失败,从而提升系统的可用性.容错性与局部应用的弹性,是一个实现了超时机制和 ...