深入理解Spring IOC(四)、 实例化开启(上)

简介: 深入理解Spring IOC(四)、 实例化开启(上)

接下来我们进入AbstractApplicationContext中的finishBeanFactoryInitialization这个方法,我们先一起看看它的代码:



代码块1
        protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // 先实例化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));
    }
    // 实例化LoadTimeWeaverAware的实现类
    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);
    // 在这里要将beanDefiniton冻结住,因为要进行实例化了,不希望beanDefiniton有任何的变化
    beanFactory.freezeConfiguration();
    // 要实例化几乎除过实现了BeanFactoryPostProcessor、BeanPostProcessor的类之外的所有类
    // 因为这两个的实现类之前已经实例化过了
    beanFactory.preInstantiateSingletons();
  }

前面的代码不属于重要的部分,我们直接看最后一处的方法preInstantiateSingletons,该方法的实现位于DefaultListableBeanFactory中:


代码块2
        @Override
  public void preInstantiateSingletons() throws BeansException {
    if (this.logger.isDebugEnabled()) {
      this.logger.debug("Pre-instantiating singletons in " + this);
    }
    List<String> beanNames;
    synchronized (this.beanDefinitionMap) {
      // this.beanDefinitionNames,创建beanDefinitionNames的副本beanNames
      // 用于后续的遍历,以允许init等方法注册新的bean定义
      // this.beanDefinitionNames 中存储的是在注册BeanDefinition的时候存进来的bean名称
      beanNames = new ArrayList<String>(this.beanDefinitionNames);
    }
    // 遍历,用bean名称初始化
    for (String beanName : beanNames) {
      // 获取beanName对应的RootBeanDefinition
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      // 如果不是抽象并且是单例,并且不是懒加载,才会去进行初始化
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
        // 1. 如果不是FactoryBean就直接初始化,是的话先拿到FactoryBean本身,再根据isEagerInit决定
        // 是否调用getObject进行初始化
        if (isFactoryBean(beanName)) {
          final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
          boolean isEagerInit;
          // 2.这个if else主要是用于判断是否需要先加载(饥饿加载)
          // isEagerInit这个变量值其实就是SmartFactoryBean中isEagerInit()方法,只不过一个是直接获取,
          // 另外一个是通过“特权”去执行
          if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
            isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
              @Override
              public Boolean run() {
                return ((SmartFactoryBean<?>) factory).isEagerInit();
              }
            }, getAccessControlContext());
          } else {
            isEagerInit = (factory instanceof SmartFactoryBean &&
                ((SmartFactoryBean<?>) factory).isEagerInit());
          }
          // 如果isEagerInit则实例化bean
          if (isEagerInit) {
            getBean(beanName);
          }
        } else {
          getBean(beanName);
        }
      }
    }
  }


我们来看代码块2的1处调用的isFactoryBean方法

代码块2.1


代码块3
        @Override
  public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
    // 1. 处理名称
    String beanName = transformedBeanName(name);
    // 2. 从缓存中拿实例并判断
    Object beanInstance = getSingleton(beanName, false);
    if (beanInstance != null) {
      return (beanInstance instanceof FactoryBean);
    // 如果this.singletonObjects包含这个beanName的key,则直接返回false
    }else if (containsSingleton(beanName)) {
      return false;
    }
    // 从beanDefinition中做检查
    // 本BeanFactory对象中没有这个beanName的BeanDefinition && 父BeanFactory是个ConfigurableBeanFactory
    if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
      return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
    }
    // 根据class判断是不是个FactoryBean
    return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
  }


首先看看代码块3中1处处理名称的逻辑:

代码块3.1


代码块4
    protected String transformedBeanName(String name) {
    // 调用canonicalName方法去处理BeanFactoryUtils.transformedBeanName的结果
    return canonicalName(BeanFactoryUtils.transformedBeanName(name));
  }


上面代码块调用的方法参数是BeanFactoryUtils中的transformedBeanName返回的,我们先来看这个方法:


代码块5
    public static String transformedBeanName(String name) {
    Assert.notNull(name, "'name' must not be null");
    String beanName = name;
    // beanName 是否以 “&” 开头,如果以它开头,将这个用String中的substring方法截掉
    while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
      beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
    }
    return beanName;
  }


很多人会疑惑,为什么以“&”开头,就截取掉呢?我们来看看BeanFactory中定义的“&”的地方:


代码块6
public interface BeanFactory {
  /**
   * Used to dereference a {@link FactoryBean} instance and distinguish it from
   * beans <i>created</i> by the FactoryBean. For example, if the bean named
   * {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
   * will return the factory, not the instance returned by the factory.
   */
  String FACTORY_BEAN_PREFIX = "&";
.....


我们可以清楚的从这个变量的注释上面看到:如果某个bean是个FactoryBean类型的东西,但是它注册进IOC容器的名称是用“&”开头,那么代表它想获取的是FactoryBean本身,而不是它的getObject所返回的对象。因此,去拿真正的bean的名称的时候是需要去掉这个前缀的。然后我们继续看代码块4调用的这个canonicalName方法

代码块4.1


代码块7
        public String canonicalName(String name) {
    String canonicalName = name;
    // Handle aliasing...
    String resolvedName;
    do {
      // 去根据别名拿真正的名称
      // aliasMap的key是别名,value是名称
      resolvedName = this.aliasMap.get(canonicalName);
      if (resolvedName != null) {
        canonicalName = resolvedName;
      }
    }
    while (resolvedName != null);
    return canonicalName;
  }


我们再回到代码块3,来看里面2处的方法,注意此时第二个参数是false:

代码块3.2


代码块8
        protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 先尝试从成品的缓存中拿成品
    Object singletonObject = this.singletonObjects.get(beanName);
    // 如果没成品并且正在创建中
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
        // 从提前曝光的对象中尝试获取
        singletonObject = this.earlySingletonObjects.get(beanName);
        // ***** 如果半成品也是null并且允许创建早期的单例引用,
        if (singletonObject == null && allowEarlyReference) {
          // 去拿对象的ObjectFactory
          ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
          if (singletonFactory != null) {
            // 通过ObjectFactory创建半成品,然后放到半成品对象的缓存中
            singletonObject = singletonFactory.getObject();
            this.earlySingletonObjects.put(beanName, singletonObject);
            this.singletonFactories.remove(beanName);
          }
        }
      }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
  }


注意注释中*****开头的,因为此时传过来的参数是false,所以在这之后的代码此时都是没有被执行的。这段代码涉及到三层缓存的概念,所谓的三层缓存,其实就是singletonObjects,earlySingletonObjects,singletonFactories这三个Map,这三层缓存对解决循环依赖有着重要的意义,如果你现在不明白,就当混个脸熟,完了回过头来看,相信会容易理解很多,现在可以理解为这个方法就是从缓存里取已经创建的bean实例的。

代码块2.2

我们继续看代码块2的第2处isEagerInit属性的获取这里,因为对于spring来说,它去拿这个isEagerInit属性,很可能是去调用第三方jar包的东西,而这个第三方jar包却需要操作一些需要权限才可以操作的东西,因此这里如果检测到SecurityManager,说明程序是有权限校验的,这时候就需要通过AccessController.doPrivileged来执行。我们接下来看这里调用的getBean方法:



代码块9
        @Override
  public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
  }


可以看到这个方法是直接调用的doGetBean,我们来看看这个方法:


代码块10
        @SuppressWarnings("unchecked")
  protected <T> T doGetBean(
      final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
      throws BeansException {
    // 1. 解析bean的名称
    final String beanName = transformedBeanName(name);
    Object bean;
    // 2.先尝试从缓存中取一波
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
      if (logger.isDebugEnabled()) {
        if (isSingletonCurrentlyInCreation(beanName)) {
          logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
              "' that is not fully initialized yet - a consequence of a circular reference");
        }else {
          logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
        }
      }
      // 3. 这块这个主要是针对FactoryBean的处理,如果只是个普通bean,则直接返回其本身
      // 如果是个FactoryBean,则要根据name判断
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    } else {
      // 4. 这个主要针对的是prototype(多例)的bean的循环依赖的检查(spring解决不了多例的循环依赖)
      if (isPrototypeCurrentlyInCreation(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
      }
      BeanFactory parentBeanFactory = getParentBeanFactory();
      // 如果父BeanFactory存在,并且本BeanFactory中不存在这个beanName的BeanDefinition
      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
        // 5. 将别名解析成真正的bean的名字
        String nameToLookup = originalBeanName(name);
        // 使用父BeanFactory创建实例
        if (args != null) {
          // Delegation to parent with explicit args.
          return (T) parentBeanFactory.getBean(nameToLookup, args);
        }else {
          // No args -> delegate to standard getBean method.
          return parentBeanFactory.getBean(nameToLookup, requiredType);
        }
      }
      // 6. 如果不是仅仅检查类型,则把beanName放到alreadyCreated缓存中
      if (!typeCheckOnly) {
        markBeanAsCreated(beanName);
      }
      // 注意哈:其实到这里,真正创建bean的流程才开始
      try {
        // 7. 拿到这个beanName对应的BeanDefinition对应的RootBeanDefinition
        final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        // 将mbd打印成json (这是作者自己增加的代码)
        System.out.println(JSON.toJSON(mbd).toString());
        // 8. 检查这个mbd是否合法
        checkMergedBeanDefinition(mbd, beanName, args);
        // 先实例化这个bean所依赖的bean,mbd.getDependsOn()是获取mbd所
        // 依赖的bean实例的名称(xml中对应bean标签depend-on属性)
        String[] dependsOn = mbd.getDependsOn();
        if (dependsOn != null) {
          for (String dependsOnBean : dependsOn) {
            // 这块这个是检查循环依赖的
            // 例:如果有这么两个类A和B,A中有个成员属性B,B中有个成员属性A,当先实例化A的时候,发现B还没有实例化
            // 然后去调用上面的getBean方法(相当于递归),然后走到这里发现B又依赖A,然后就报异常了
            // 这个会在两个bean标签的depend-on属性相互指向对方时发生
            if (isDependent(beanName, dependsOnBean)) {
              throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                  "Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
            }
            // 9. 将依赖关系注册
            registerDependentBean(dependsOnBean, beanName);
            // 然后实例化依赖的那个bean
            getBean(dependsOnBean);
          }
        }
        // 这里开始创建mbd对应的bean
        // 创建单例
        if (mbd.isSingleton()) {
          // 10. 获取bean实例
          sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
            @Override
            public Object getObject() throws BeansException {
              try {
                //  调用创建bean的方法
                return createBean(beanName, mbd, args);
              }catch (BeansException ex) {
                destroySingleton(beanName);
                throw ex;
              }
            }
          });
          // 返回bean本身,(这个方法我们之前讲过,是针对FactoryBean处理的那个方法)
          bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        // 创建prototype的bean
        }else if (mbd.isPrototype()) {
          // 如果是个prototype的实例,那就创建个新的
          Object prototypeInstance = null;
          try {
            // 11. 创建prototype前的检查
            beforePrototypeCreation(beanName);
            // 调用创建bean的方法
            prototypeInstance = createBean(beanName, mbd, args);
          }finally {
            // 12.创建prototype后的检查
            afterPrototypeCreation(beanName);
          }
          // 返回bean本身,(和上面if一个方法)
          bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
        // 创建其他scope的bean
        }else {
          String scopeName = mbd.getScope();
          // 拿到对应scope的缓存
          final Scope scope = this.scopes.get(scopeName);
          if (scope == null) {
            throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
          }
          try {
            // 创建bean实例,注意这里重写了ObjectFactory的getObject方法
            Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
              @Override
              public Object getObject() throws BeansException {
                // 创建prototype前的检查
                beforePrototypeCreation(beanName);
                try {
                  // 调用创建bean的方法
                  return createBean(beanName, mbd, args);
                }finally {
                  // 创建prototype后的检查
                  afterPrototypeCreation(beanName);
                }
              }
            });
            // 返回bean本身,(和上面if一个方法)
            bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
          }catch (IllegalStateException ex) {
            throw new BeanCreationException(beanName,
                "Scope '" + scopeName + "' is not active for the current thread; " +
                "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                ex);
          }
        }
      }catch (BeansException ex) {
        cleanupAfterBeanCreationFailure(beanName);
        throw ex;
      }
    }
    // 检查类型,如果不是结果所需要的类型,则尝试类型转换
    if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
      try {
        return getTypeConverter().convertIfNecessary(bean, requiredType);
      }catch (TypeMismatchException ex) {
        if (logger.isDebugEnabled()) {
          logger.debug("Failed to convert bean '" + name + "' to required type [" +
              ClassUtils.getQualifiedName(requiredType) + "]", ex);
        }
        throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
    }
    return (T) bean;
  }


这个方法代码比较长,我们对着我的注释,一个一个来看,1处在上面已经讲过,这里和上面的逻辑是完全一样的,我们来看代码块10中2处的代码所调用的方法:

代码块10.2


代码块11
        @Override
  public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
  }


这里调用的方法还是代码块8的那个方法,只不过注意此时参数为true了,true和上面的false有什么区别呢?我们可以翻到代码块8看看,当这个参数为true的时候,是允许使用ObjectFactory来创建早期的引用的,不过你可能还不明白什么是早期引用,没关系,先记住这个问题,继续往下看,自然会明白。

我们继续回到代码块10中,去看第3处代码,你应该注意到,能走到这处,说明上面从缓存中取出来的sharedInstance应该不是null,并且本方法参数中args要为null,我们在代码块9中可以看到args确实是null,所以可以肯定,如果sharedInstance不是null,那的确是可以进到3这里来的:我们来看看3处调用的方法。

目录
相关文章
|
4天前
|
XML Java 数据格式
Spring框架入门:IoC与DI
【5月更文挑战第15天】本文介绍了Spring框架的核心特性——IoC(控制反转)和DI(依赖注入)。IoC通过将对象的创建和依赖关系管理交给容器,实现解耦。DI作为IoC的实现方式,允许外部注入依赖对象。文章讨论了过度依赖容器、配置复杂度等常见问题,并提出通过合理划分配置、使用注解简化管理等解决策略。同时,提醒开发者注意过度依赖注入和循环依赖,建议适度使用构造器注入和避免循环引用。通过代码示例展示了注解实现DI和配置类的使用。掌握IoC和DI能提升应用的灵活性和可维护性,实践中的反思和优化至关重要。
18 4
|
4天前
|
Java 测试技术 开发者
Spring IoC容器通过依赖注入机制实现控制反转
【4月更文挑战第30天】Spring IoC容器通过依赖注入机制实现控制反转
22 0
|
4天前
|
XML Java 程序员
Spring特性之二——IOC控制反转
Spring特性之二——IOC控制反转
16 4
|
4天前
|
安全 Java 开发者
在Spring框架中,IoC和AOP是如何实现的?
【4月更文挑战第30天】在Spring框架中,IoC和AOP是如何实现的?
24 0
|
4天前
|
XML Java 程序员
什么是Spring的IoC容器?
【4月更文挑战第30天】什么是Spring的IoC容器?
20 0
|
4天前
|
Java Spring 容器
【Spring系列笔记】IOC与DI
IoC 和 DI 是面向对象编程中的两个相关概念,它们主要用于解决程序中的依赖管理和解耦问题。 控制反转是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入和依赖查找。
35 2
|
4天前
|
Java 测试技术 数据库连接
Spring中ioc的优点
总之,Spring中的IoC提供了一种更加灵活、可维护、可测试和可扩展的方式来管理组件之间的依赖关系,从而提高了应用程序的质量和可维护性。这使得开发人员能够更专注于业务逻辑而不是底层的技术细节。
32 1
|
4天前
|
Java 应用服务中间件 Spring
|
4天前
|
XML Java 数据格式
Spring IOC的源码解析
【4月更文挑战第17天】Spring IOC(控制反转)的核心功能是通过依赖注入(DI)来管理对象的创建和它们之间的依赖关系。要深入理解Spring IOC的工作原理,我们可以从其源码分析入手,特别是关注如何创建和管理Bean以及依赖注入的实现
22 1
|
4天前
|
XML Java 数据格式
Spring IOC—基于XML配置和管理Bean 万字详解(通俗易懂)
Spring 第二节 IOC—基于XML配置和管理Bean 万字详解!。
97 5