小言_互联网的博客

Spring 如何从 IoC 容器中获取对象?

254人阅读  评论(0)

前情回顾

前面几篇文章主要分析了 Spring IoC 容器如何初始化,以及解析和注册我们定义的 bean 信息。

其中,「Spring 中的 IoC 容器」对 Spring 中的容器做了一个概述,「Spring IoC 容器初始化」和「Spring IoC 容器初始化(2)」分析了 Spring 如何初始化 IoC 容器,「Spring 是如何解析 <bean> 标签的?」分析了 Spring 如何解析 <bean> 标签及其子标签,并注册到 BeanFactory。

主要流程如下:

IoC 容器已经建立,而且把我们定义的 bean 信息放入了容器,那么如何从容器中获取对象呢?

本文继续分析。

配置及测试代码

为便于查看,这里再贴一下 bean 配置文件和测试代码。

  • 配置文件 application-ioc.xml


   
  1. <?xml version= "1.0" encoding= "UTF-8"?>
  2. <beans xmlns= "http://www.springframework.org/schema/beans"
  3.        xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
  4.        xsi:schemaLocation= "http://www.springframework.org/schema/beans
  5.        http://www.springframework.org/schema/beans/spring-beans.xsd">
  6.     <bean id= "person" class= "com.jaxer.spring.ioc.Person">
  7.         <property name= "pet" ref= "dog"/>
  8.     </bean>
  9.     <bean id= "dog" class= "com.jaxer.spring.ioc.Dog">
  10.         <property name= "age" value= "1"/>
  11.         <property name= "owner" ref= "person"/>
  12.     </bean>
  13. </beans>
  • 测试代码


   
  1. public class IocTests {
  2.     @Test
  3.     public void test01() {
  4.         ApplicationContext context =  new ClassPathXmlApplicationContext( "application-ioc.xml");
  5.         System.out. println(context.getBean( "person"));
  6.         System.out. println(context.getBean( "dog"));
  7.     }
  8. }
  9. /*
  10.  * 输出结果:
  11.  *  Person{id=12, name='Jack-12'}
  12.  *  Dog{age=1}
  13.  */

如何从容器获取对象?

从容器中获取对象是通过 BeanFactory#getBean 方法,它有多个重载的方法,但最终都是通过

AbstractBeanFactory#doGetBean 方法来实现的。doGetBean 方法代码如下:


   
  1. public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
  2.      // ...
  3.     protected <T> T doGetBean(
  4.             String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
  5.             throws BeansException {
  6.         String beanName = transformedBeanName(name);
  7.         Object bean;
  8.          // 从缓存中获取单例 bean 对象
  9.         Object sharedInstance = getSingleton(beanName);
  10.          if (sharedInstance != null && args == null) {
  11.              // ...
  12.              // 处理 FactoryBean 的场景
  13.             bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
  14.         }
  15.         
  16.          // 缓存中不存在 bean 对象
  17.          else {
  18.              if (isPrototypeCurrentlyInCreation(beanName)) {
  19.                 throw  new BeanCurrentlyInCreationException(beanName);
  20.             }
  21.              // bean 对象在父容器中,则从父容器中获取 bean 对象
  22.             BeanFactory parentBeanFactory = getParentBeanFactory();
  23.              if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
  24.                  // Not found -> check parent.
  25.                 String nameToLookup = originalBeanName(name);
  26.                  if (parentBeanFactory instanceof AbstractBeanFactory) {
  27.                      return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
  28.                             nameToLookup, requiredType, args, typeCheckOnly);
  29.                 }
  30.                  else  if (args != null) {
  31.                      // Delegation to parent with explicit args.
  32.                      return (T) parentBeanFactory.getBean(nameToLookup, args);
  33.                 }
  34.                  else  if (requiredType != null) {
  35.                      // No args -> delegate to standard getBean method.
  36.                      return parentBeanFactory.getBean(nameToLookup, requiredType);
  37.                 }
  38.                  else {
  39.                      return (T) parentBeanFactory.getBean(nameToLookup);
  40.                 }
  41.             }
  42.              // 是否只做类型检查
  43.              if (!typeCheckOnly) {
  44.                 markBeanAsCreated(beanName);
  45.             }
  46.             try {
  47.                  // 获取 BeanDefinition
  48.                 RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
  49.                 checkMergedBeanDefinition(mbd, beanName, args);
  50.                  // 获取依赖的 bean 对象
  51.                  // 若创建一个 bean 对象时依赖其他对象,则先创建被依赖对象
  52.                 String[] dependsOn = mbd.getDependsOn();
  53.                  if (dependsOn != null) {
  54.                      for (String dep : dependsOn) {
  55.                          if (isDependent(beanName, dep)) {
  56.                              // ...
  57.                         }
  58.                         registerDependentBean(dep, beanName);
  59.                         try {
  60.                             getBean(dep);
  61.                         }
  62.                         catch (NoSuchBeanDefinitionException ex) {
  63.                              // ...
  64.                         }
  65.                     }
  66.                 }
  67.                  // 创建 scope 为 singleton(单例)的对象
  68.                  if (mbd.isSingleton()) {
  69.                     sharedInstance = getSingleton(beanName, () -> {
  70.                         try {
  71.                              return createBean(beanName, mbd, args);
  72.                         }
  73.                         catch (BeansException ex) {
  74.                              // ...
  75.                         }
  76.                     });
  77.                      // 处理 FactoryBean 的场景
  78.                     bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
  79.                 }
  80.                  // 创建 scope 为 prototype 的对象
  81.                  else  if (mbd.isPrototype()) {
  82.                      // It's a prototype -> create a new instance.
  83.                     Object prototypeInstance = null;
  84.                     try {
  85.                         beforePrototypeCreation(beanName);
  86.                         prototypeInstance = createBean(beanName, mbd, args);
  87.                     }
  88.                     finally {
  89.                         afterPrototypeCreation(beanName);
  90.                     }
  91.                      // 处理 FactoryBean 的场景
  92.                     bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
  93.                 }
  94.                  // 创建其他类型对象
  95.                  else {
  96.                     String scopeName = mbd.getScope();
  97.                      if (!StringUtils.hasLength(scopeName)) {
  98.                         throw  new IllegalStateException( "No scope name defined for bean ´" + beanName +  "'");
  99.                     }
  100.                     Scope scope = this.scopes.get(scopeName);
  101.                      if (scope == null) {
  102.                         throw  new IllegalStateException( "No Scope registered for scope name '" + scopeName +  "'");
  103.                     }
  104.                     try {
  105.                         Object scopedInstance = scope.get(beanName, () -> {
  106.                             beforePrototypeCreation(beanName);
  107.                             try {
  108.                                  return createBean(beanName, mbd, args);
  109.                             }
  110.                             finally {
  111.                                 afterPrototypeCreation(beanName);
  112.                             }
  113.                         });
  114.                          // 处理 FactoryBean 的场景
  115.                         bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
  116.                     }
  117.                     catch (IllegalStateException ex) {
  118.                          // ...
  119.                     }
  120.                 }
  121.             }
  122.             catch (BeansException ex) {
  123.                 cleanupAfterBeanCreationFailure(beanName);
  124.                 throw ex;
  125.             }
  126.         }
  127.          // 类型检查
  128.          if (requiredType != null && !requiredType.isInstance(bean)) {
  129.             try {
  130.                 T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
  131.                  if (convertedBean == null) {
  132.                     throw  new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
  133.                 }
  134.                  return convertedBean;
  135.             }
  136.             catch (TypeMismatchException ex) {
  137.                  // ...
  138.             }
  139.         }
  140.          return (T) bean;
  141.     }
  142. }

获取 bean 对象主要就是通过这个 doGetBean 方法实现的。

该方法虽然看起来稍微有点长,但是呢,它内部的实现更长、更复杂。不过也是有迹可循的,莫慌。

本文先看下这个方法的整体流程,内部逻辑后面再慢慢研究。先上流程图:

代码虽然有点长,但梳理下来其实也没那么复杂了。

这个方法主要做了什么呢?

当从容器中获取 bean 对象时,首先从缓存中获取。如果缓存中存在,处理 FactoryBean 的场景。

BeanFactory 和 FactoryBean,这哥俩长得很像,也有个别面试题可能会问到。

嗯……以后有机会单独分析?

如果缓存中没有,先去父容器获取,前面创建 BeanFactory 时可以指定 parent 参数,就是那个。

不在父容器中,若 bean 对象依赖了其他对象,则先创建被依赖的 bean 对象,再根据 <bean> 标签的 scope 属性去创建相应的 bean 对象。

是不是有点像我们平时写查询接口时、先从缓存查询,缓存中没的话再查询 DB?

道理是一样的,空间换时间。

小结

先整体,后细节。

本文先从整体上分析了如何从 Spring IoC 容器中获取 bean 对象,内容不多,后文再详细分解吧。

休息会~


转载:https://blog.csdn.net/u010551118/article/details/114312307
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场