转载

Spring IoC - IoC 容器初始化 源码解析

Spring IoC - IoC 容器初始化 源码解析

前言

本章主要内容是由以下部分组成,

  • Spring 中容器初始化入口
  • 以最经典的ClassPathXmlApplicationContext 为例,讲解Spring IoC 的容器初始化过程

在学习源码的过程当中,我想强调两点:

  1. 一定要学会抓重点,归纳核心类、核心方法、核心步骤。
  2. 理解类、变量、方法名的命名,Spring 源码的命名是很讲究的,很多时候是自解释的
  3. 一定要学会看Java doc ,同上,这种顶级的框架的java doc 描述非常的详尽

Spring 容器初始化入口

启动容器,实际上指的就是实例化ApplicationContext的这个动作。只是在不同情况下可能有不同的表现形式。

  1. ClassPathXmlApplicationContext 通过XML配置
ApplicationContext context = new ClassPathXmlApplicationContext(applicationContext.xml");
  1. AnnotationConfigApplicationContext 通过java config 类配置
@Configuration
@ComponentScan("ric.study.demo.ioc")
public class BeanDemoConfig {
    public static void main(String... strings) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(BeanDemoConfig.class);
        System.out.println("Spring container started and is ready");
        ...
    }
}

类似前面这两种 new ***ApplicationContext 的方式,很少会用于直接的生产开发。一般都是我们自己在demo中或者单元测试中会用到。

  1. WebApplicationContext SpringMVC

这个实际上是我们平常最常用的初始化方式,Spring MVC 中 ServletContext 为 Spring 的 IoC容器提供了宿主环境。是通过ContextLoaderListener 的初始化来建立的。

WebApplicationContext 的初始化调用链路:ContextLoaderListener.contextInitialized --> ContextLoader.initWebApplicationContext --> ContextLoader.createWebApplicationContext --> ContextLoader.determineContextClass --> ContextLoader.determineContextClass。

底层是通过反射来实例化的。

protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
        Class<?> contextClass = determineContextClass(sc);
        if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
            throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
                    "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
        }
        return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
    }

这块内容先简要提一下,属于SpringMVC的内容,不是我们今天要讲的Spring IoC 模块的知识。

容器初始化 源码解析

现在让我们正式开始的源码解读。会从最经典的ClassPathXmlApplicationContext 上下文为起点,来描述整个过程。

在说明之前,我想了想还是觉得把整个IoC容器初始化的关键步骤为大家梳理一下,以便于大家能在心里有个大概的脉络,更容易读懂源码,更容易抓住重点。再重复提一句,看源码一定要学会抓重点,归纳核心类、核心方法、核心步骤。

ClassPathXmlApplicationContext 的容器初始化我们大致分为下面几步:

  1. BeanDefinition 的 Resource 定位

    这里的Resource定位 是通过继承ResourceLoader 获得的,ResourceLoader代表了 加载资源的一种方式,正是策略模式的实现 。

  2. 从 Resource中解析、载入BeanDefinition
  3. BeanDefinition 在IoC 容器中的注册

前面说了,实例化这个上下文,就是在启动 IoC 容器。那我们肯定要从它的构造函数入手。

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {

        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }

入参中的 configLocations 在这里就是你XML配置文件 的 classpath。

setConfigLocations(configLocations); 我这里不展开讲,内容不复杂,就是把一些带有占位符的地址解析成实际的地址。

再之后就是 refresh() ,我们说的容器初始化,就是在这里面进行的,这里取名为refresh, 是因为容器启动之后,再调用 refresh() 会刷新IoC 容器 。

这里先放上IoC容器初始化的时序图,方便理解,

Spring IoC - IoC 容器初始化 源码解析

refresh() 的源码:

@Override
public void refresh() throws BeansException, IllegalStateException {
   // 来个锁,不然 refresh() 还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛
   synchronized (this.startupShutdownMonitor) {

      // 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
      prepareRefresh();

      // 这步比较关键,这步完成后,配置文件就会解析成一个个 Bean 定义,注册到 BeanFactory 中,
      // 当然,这里说的 Bean 还没有初始化,只是配置信息都提取出来了,
      // 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 map)
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
      // 这块待会会展开说
      prepareBeanFactory(beanFactory);

      try {
         // 【这里需要知道 BeanFactoryPostProcessor 这个知识点,Bean 如果实现了此接口,
         // 那么在容器初始化以后,Spring 会负责调用里面的 postProcessBeanFactory 方法。】

         // 这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化
         // 具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类或做点什么事
         postProcessBeanFactory(beanFactory);
         // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
         invokeBeanFactoryPostProcessors(beanFactory);

         // 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
         // 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
         // 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化
         registerBeanPostProcessors(beanFactory);

         // 初始化当前 ApplicationContext 的 MessageSource,国际化不是重点,不展开
         initMessageSource();

         // 初始化当前 ApplicationContext 的事件广播器,这里也不展开了
         initApplicationEventMulticaster();

         // 从方法名就可以知道,典型的模板方法(钩子方法),
         // 具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
         onRefresh();

         // 注册事件监听器,监听器需要实现 ApplicationListener 接口。这也不是我们的重点,过
         registerListeners();

         // 重点,重点,重点
         // 初始化所有的 singleton beans
         //(lazy-init 的除外)
         finishBeanFactoryInitialization(beanFactory);

         // 最后,广播事件,ApplicationContext 初始化完成
         finishRefresh();
      }

      catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }

         // Destroy already created singletons to avoid dangling resources.
         // 销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
         destroyBeans();
         // Reset 'active' flag.
         cancelRefresh(ex);
         throw ex;
      }

      finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();
      }
   }
}

我会从上述流程中,挑以下几个进行分析,

  1. prepareRefresh() 创建容器前的准备工作
  2. obtainFreshBeanFactory() 创建 BeanFactory
  3. prepareBeanFactory(beanFactory) 对BeanFactory进行一些特征的设置工作
  4. finishBeanFactoryInitialization(beanFactory); 初始化所有的 singleton beans(DI的入口)

1. prepareRefresh() 创建容器前的准备工作

protected void prepareRefresh() {
   // 记录启动时间,
   // 将 active 属性设置为 true,closed 属性设置为 false,它们都是 AtomicBoolean 类型
   this.startupDate = System.currentTimeMillis();
   this.closed.set(false);
   this.active.set(true);

   if (logger.isInfoEnabled()) {
      logger.info("Refreshing " + this);
   }

   // Initialize any placeholder property sources in the context environment
   initPropertySources();

   // 校验 xml 配置文件
   getEnvironment().validateRequiredProperties();

   this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}

2.★ obtainFreshBeanFactory() 创建 Bean 容器,加载并注册 Bean

IoC初始化里面最重要的部分。

关键是以下几步,

  • 初始化BeanFactory
  • 加载Bean
  • 注册Bean
  • ...

注意:这步完成后,Bean 并没有完成初始化,实际的实例并没有被创建。

源码位置: AbstractApplicationContext#obtainFreshBeanFactory()

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        // 关闭旧的 BeanFactory (如果有),创建新的 BeanFactory,加载 Bean 定义、注册 Bean 等等
        refreshBeanFactory();
        // 返回上一步刚刚创建的BeanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }

源码位置: AbstractRefreshableApplicationContext#refreshBeanFactory()

protected final void refreshBeanFactory() throws BeansException {
        // 如果 ApplicationContext 已经加载过 BeanFactory,销毁所有的Bean,关闭BeanFactory
        // 注意点:应用中BeanFactory是可以有多个的,这里可不是说全局是否有BeanFactory
        // 而是说当前的ApplicationContext有没有BeanFactory!
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            // 初始化一个 DefaultListableBeanFactory
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            // 用于 BeanFactory 的序列化,一般人应该用不到吧...
            beanFactory.setSerializationId(getId());
            // 下面是两个重点方法
            // 设置 BeanFactory 的两个重要属性
            // 是否允许 Bean 覆盖、是否允许循环引用 TODO 2.1
            customizeBeanFactory(beanFactory);
            
            // 加载BeanDefinition到BeanFactory  单独拉出来讲
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

看到这里的时候,可以感觉到一个设计思路,ApplicationContext 继承自 BeanFactory,但是 它不应该被理解为 BeanFactory 的实现类,而是说其内部持有一个实例化的 BeanFactory(DefaultListableBeanFactory)。以后所有的 BeanFactory 相关的操作其实是委托给这个实例来处理的 。

2.1 customizeBeanFactory

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
        if (this.allowBeanDefinitionOverriding != null) {
            beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        if (this.allowCircularReferences != null) {
            beanFactory.setAllowCircularReferences(this.allowCircularReferences);
        }
    }

BeanDefinition 的覆盖问题可能会有开发者碰到这个坑,就是在配置文件中定义 bean 时使用了相同的 id 或 name, 默认情况下,allowBeanDefinitionOverriding 属性为 null(Boolean类型),如果在同一配置文件中重复了,会抛错,但是如果不是同一配置文件中,会发生覆盖 。

循环引用也很好理解:A 依赖 B,而 B 依赖 A。或 A 依赖 B,B 依赖 C,而 C 依赖 A。

默认情况下,Spring 允许循环依赖,当然如果你在 A 的构造方法中依赖 B,在 B 的构造方法中依赖 A 是不行的。

2.2 ★ loadBeanDefinitions(beanFactory) 加载BeanDefinition

看下这个方法的声明,

/**
     * Load bean definitions into the given bean factory, typically through
     * delegating to one or more bean definition readers.
     * @param beanFactory the bean factory to load bean definitions into
     * @throws BeansException if parsing of the bean definitions failed
     * @throws IOException if loading of bean definition files failed
     * @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader
     * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
     */
    protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
            throws BeansException, IOException;

在ClassPathXmlApplicationContext 是按照解析XML的加载方式。看javadoc的描述,是通过 XmlBeanDefinitionReader 来载入Bean Definitions。

/**
     * Loads the bean definitions via an XmlBeanDefinitionReader.
     * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
     * @see #initBeanDefinitionReader
     * @see #loadBeanDefinitions
     */
    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // Create a new XmlBeanDefinitionReader for the given BeanFactory.
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // Configure the bean definition reader with this context's
        // resource loading environment.
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,
        // 初始化Reader 不重要,看下这个方法的javadoc就很好理解了
        initBeanDefinitionReader(beanDefinitionReader);
        // 真正重要的步骤!!
        // 用Reader去加载XML配置
        loadBeanDefinitions(beanDefinitionReader);
    }

loadBeanDefinitions(beanDefinitionReader)

/**
     * Load the bean definitions with the given XmlBeanDefinitionReader.
     * 看这句注释:this method is just supposed to load and/or register bean definitions.
     */
    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            // 这个分支,通过路径名去获取Resource,会和上面的方法殊途同归
            reader.loadBeanDefinitions(configLocations);
        }
    }

AbstractBeanDefinitionReader#loadBeanDefinitions(Resource... resources)

@Override
    public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
        Assert.notNull(resources, "Resource array must not be null");
        int counter = 0;
        for (Resource resource : resources) {
            // 遍历解析XML文件,加载 BeanDefinition
            counter += loadBeanDefinitions(resource);
        }
        return counter;
    }

接下去的源码不细讲,这里载入分为两大步,

BeanDefinitionDocumentReader

这里我觉得核心知识点就是Spring Bean规则的解析,简单点来说,里面包含了我们在XML配置的那些信息,怎么解析成容器中 BeanDefinition的规则和步骤。这部分由于和主要流程关系不大,我就没贴源码解析了,会占掉很大的篇幅,影响阅读和理解。

在这因为Spring 的 Bean配置方式有很多,解析配置信息到BeanDefinition的实现方式也有很多,XML又是现在少用的方式,所以关于XML中的Spring Bean规则的解析的详细源码就先略过了。有兴趣的同学可以阅读《Spring 技术内幕》这本书或者其他的文章书籍。

2.3 注册Bean

虽然上面说了不讲XML 解析 成 BeanDefinition的过程源码。但是上述 loadBeanDefinitions(resource) 包含了我们关键的第三步,注册Bean。这部分还是需要填一下的。

注意一下前面实例化Reader的代码,

XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    /**
     * Create new XmlBeanDefinitionReader for the given bean factory.
     * @param registry the BeanFactory to load bean definitions into,
     * in the form of a BeanDefinitionRegistry
     */
    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
        super(registry);
    }

beanDefinitionReader 获取到 beanFactory 的引用,这个引用会在beanDefinition 被加载完毕要注册的时候使用到。可以看到是因为 BeanDefinitionRegistry 这个接口,赋予了BeanFactory注册BeanDefinition的特性。

具体执行“注册Bean”这一动作的源码,按照上述 loadBeanDefinitions(resource) 方法一直走下去的话是在 DefaultBeanDefinitionDocumentReader#processBeanDefinition() 方法中,

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // Register the final decorated instance.
                // 注册Bean
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }

源码位置 BeanDefinitionReaderUtils#registerBeanDefinition()

/**
     * Register the given bean definition with the given bean factory.
     * @param definitionHolder the bean definition including name and aliases
     * @param registry the bean factory to register with
     * @throws BeanDefinitionStoreException if registration failed
     */
    public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {

        // Register bean definition under primary name.
        // 注册
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

        // Register aliases for bean name, if any.
        // 如果还有别名的,把别名全都注册一遍
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                // 到时候获取的时候,就是先把Alias转化成BeanName,再去获取对应的Bean
                registry.registerAlias(beanName, alias);
            }
        }
    }

上面的 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); ,

源码位置 DefaultListableBeanFactory#registerBeanDefinition()

@Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        // 注意哦,这里是有关 “允许Bean覆盖” 的逻辑代码
        // 记得这个配置 allowBeanDefinitionOverriding
        BeanDefinition oldBeanDefinition;

        // beanDefinitionMap 是存放所有BeanDefinition的容器
        oldBeanDefinition = this.beanDefinitionMap.get(beanName);
        
        // not null 说明,有重复名称的bean
        if (oldBeanDefinition != null) {
            if (!isAllowBeanDefinitionOverriding()) {
                // 判断是否允许覆盖,不允许直接抛异常
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                        "': There is already [" + oldBeanDefinition + "] bound.");
            }
            else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                // 打下debug log...用框架定义的 Bean 覆盖用户自定义的 Bean
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            }
            else if (!beanDefinition.equals(oldBeanDefinition)) {
                // 打下debug log...用新的 Bean 覆盖旧的 Bean
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            else {
                // 打下debug log...用同等的 Bean 覆盖旧的 Bean
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            // 覆盖了
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
            // 判断是否有其他Bean已经开始初始化了
            if (hasBeanCreationStarted()) {
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                // 检测创建 Bean 阶段已经开启,需要对 beanDefinitionMap 进行并发控制
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            }
            else {
                // Still in startup registration phase
                // 最最最正常的分支
                
                //  注册 到 容器中
                this.beanDefinitionMap.put(beanName, beanDefinition);
                // 这是一个 ArrayList,所以会按照 bean 配置的顺序保存每一个注册的 Bean 的名字
                this.beanDefinitionNames.add(beanName);
                // 这是个 LinkedHashSet,代表的是手动注册的 singleton bean,
                // 注意这里是 remove 方法,到这里的 Bean 当然不是手动注册的
                 // 手动指的是通过调用以下方法注册的 bean :
                 // registerSingleton(String beanName, Object singletonObject)
                 // 这不是重点,解释只是为了不让大家疑惑。Spring 会在后面"手动"注册一些 Bean,
                 // 如 "environment"、"systemProperties" 等 bean,我们自己也可以在运行时注册 Bean 到容器中的
                this.manualSingletonNames.remove(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        if (oldBeanDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }

以上,只是 obtainFreshBeanFactory() 的内容,到这里,BeanFactory也算是实例化完成了。

这里还是来个分割线。因为接下去会讲refresh() 方法的后续步骤的知识点,我想读者同学在这里最好最好,回到 前面 refresh() 总述的部分,再看一下。(如果你是一边还打开着IDE,在对照阅读调试的话,回到最前面refresh() 方法,再继续往下)

3. prepareBeanFactory(beanFactory)

此方法负责对BeanFactory进行一些特征的设置工作,这些特征在代码中都有体现。

/**
     * Configure the factory's standard context characteristics,
     * such as the context's ClassLoader and post-processors.
     * @param beanFactory the BeanFactory to configure
     */
    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Tell the internal bean factory to use the context's class loader etc.
        // BeanFactory 需要加载类,所以需要获得类加载器
        // 设置当前ApplicationContext的类加载器
        beanFactory.setBeanClassLoader(getClassLoader());
        // 内含 Spel 解释器,暂时不重要
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        // 注册属性编辑器,暂时不重要
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

        // Configure the bean factory with context callbacks.
        // 添加一个ApplicationContextAwareProcessor,主要针对实现了Aware接口的Bean
        // 延伸知识:在Spring中我们自己的bean可以通过实现EnvironmentAware等一系列Aware接口,获取到Spring内部的一些对象。
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        // 依赖解析忽略, 设置哪些接口在进行依赖注入的时候应该被忽略
        // 通俗来说,下面几行的意思就是,如果某个 bean 依赖于以下几个接口的实现类,在自动装配的时候忽略它们,
           // Spring 会通过其他方式来处理这些依赖。
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

        // BeanFactory interface not registered as resolvable type in a plain factory.
        // MessageSource registered (and found for autowiring) as a bean.
        /**
        * 下面几行就是为特殊的几个 bean 赋值,如果有 bean 依赖了以下几个,会注入这边相应的值,
        * 之前我们说过,"当前 ApplicationContext 持有一个 BeanFactory",这里解释了第一行
        * ApplicationContext 还继承了 ResourceLoader、ApplicationEventPublisher、MessageSource
        * 所以对于这几个依赖,可以赋值为 this,注意 this 是一个 ApplicationContext
        * 那这里怎么没看到为 MessageSource 赋值呢?那是因为 MessageSource 被注册成为了一个普通的 bean
        */
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);

        // Register early post-processor for detecting inner beans as ApplicationListeners.
        // 这个 BeanPostProcessor 也很简单,在 bean 实例化后,如果是 ApplicationListener 的子类,
           // 这个postProcessor的作用就是将其添加到 listener 列表中,可以理解成:注册 事件监听器
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

        // Detect a LoadTimeWeaver and prepare for weaving, if found.
        // 这里涉及到特殊的 bean,名为:loadTimeWeaver,AspectJ相关内容
        // 不是这里的重点,放过我
        if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            // Set a temporary ClassLoader for type matching.
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
        // Register default environment beans.
        // Spring 的“智能”操作,会帮我们默认注册一些有用的Bean
        //  如果没有定义 "environment" 这个 bean,那么 Spring 会 "手动" 注册一个
        if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
        }
        // 如果没有定义 "systemProperties" 这个 bean,那么 Spring 会 "手动" 注册一个
        if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
        }
        // 如果没有定义 "systemEnvironment" 这个 bean,那么 Spring 会 "手动" 注册一个
        if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
        }
    }

4. ★ finishBeanFactoryInitialization(beanFactory) 实例化所有单例

这里会负责初始化所有的 singleton beans。

Spring 会在这个阶段完成所有的 singleton beans 的实例化。

到目前为止,应该说 BeanFactory 已经创建完成,并且所有的实现了 BeanFactoryPostProcessor 接口的 Bean 都已经初始化并且其中的 postProcessBeanFactory(factory) 方法已经得到回调执行了。而且 Spring 已经“手动”注册了一些特殊的 Bean,如 environment 、 systemProperties 等。

剩下的就是初始化 singleton beans 了,我们知道它们是单例的, 如果没有设置懒加载 ,那么 Spring 会在接下来初始化所有的 singleton beans。

源码位置: AbstractApplicationContext#finishBeanFactoryInitialization()

/**
     * Finish the initialization of this context's bean factory,
     * initializing all remaining singleton beans.
     */
    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        // Initialize conversion service for this context.
        // 初始化"conversionService"的bean,此接口用于类型之间的转化,不是重点,放过我,自己去看
        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(new StringValueResolver() {
                @Override
                public String resolveStringValue(String strVal) {
                    return 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) {
            // 先初始化 LoadTimeWeaverAware 类型的bean
            getBean(weaverAwareName);
        }

        // Stop using the temporary ClassLoader for type matching.
        beanFactory.setTempClassLoader(null);

        // Allow for caching all bean definition metadata, not expecting further changes.
        // 看方法名就知道了,冻结所有BeanDefinition的元数据了
        // 没什么别的目的,因为到这一步的时候,Spring 已经开始预初始化 singleton beans 了,
        // 肯定不希望这个时候还出现 bean 定义解析、加载、注册。
        beanFactory.freezeConfiguration();

        // Instantiate all remaining (non-lazy-init) singletons.
        // 开始初始化,进来看吧,重点在里面
        beanFactory.preInstantiateSingletons();
    }

源码位置: DefaultListableBeanFactory#preInstantiateSingletons()

@Override
    public void preInstantiateSingletons() throws BeansException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Pre-instantiating singletons in " + this);
        }
        
        // copy 一个包含所有BeanName的集合副本
        List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

        // 触发所有非懒加载的 singleton beans的初始化
        for (String beanName : beanNames) {
            // Bean 可能有继承parent的关系,获取合并后的RootBeanDefinition
            // 这个知识点用的很少的
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            
            // 非抽象、非懒加载的singletons
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                // FactoryBean知识点,不了解的看另一篇文章或者自己google
                if (isFactoryBean(beanName)) {
                    // FactoryBean 会在 beanName前面加前缀"&"
                    final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
                    boolean isEagerInit;
                    // SmartFactoryBean, 非重点,没深入了解,放过我
                    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());
                    }
                    if (isEagerInit) {
                        getBean(beanName);
                    }
                }
                else {
                    // 正常的bean都到这里来了,重点哦,里面进行初始化了
                    // 调用链很复杂,单独拉出来讲,先继续
                    getBean(beanName);
                }
            }
        }
        
        // 前面流程走完,说明所有的非懒加载singletonBean 完成了初始化

        // Trigger post-initialization callback for all applicable beans...
        // 看注释就懂了,如果我们定义的 bean 是实现了 SmartInitializingSingleton 接口的,
        // 那么在这里得到回调,忽略它吧。
        for (String beanName : beanNames) {
            Object singletonInstance = getSingleton(beanName);
            if (singletonInstance instanceof SmartInitializingSingleton) {
                final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
                if (System.getSecurityManager() != null) {
                    AccessController.doPrivileged(new PrivilegedAction<Object>() {
                        @Override
                        public Object run() {
                            smartSingleton.afterSingletonsInstantiated();
                            return null;
                        }
                    }, getAccessControlContext());
                }
                else {
                    smartSingleton.afterSingletonsInstantiated();
                }
            }
        }
    }

小知识点 关于 lazy-init

ApplicationContext 实现的默认行为就是在启动时将所有 singleton bean提前进行实例化。 提前实例化意味着作为初始化过程的一部分,ApplicationContext 实例会创建并配置所有的singleton bean。通常情况下这是件好事,因为这样在配置中的任何错误就会即刻被发现(否则的话可能要花几个小时甚至几天) 。

有时候这种默认处理可能并 不是 你想要的。如果你不想让一个singleton bean 在ApplicationContext 实现在初始化时被提前实例化,那么可以将bean设置为延迟实例化。一个延迟初始化bean 将告诉IoC 容器是在启动时还是在第一次被用到时实例化。

需要说明的是, 如果一个bean被设置为延迟初始化,而另一个非延迟初始化的singleton bean 依赖于它,那么当ApplicationContext 提前实例化singleton bean时,它必须也确保所有上述singleton 依赖bean也被预先初始化,当然也包括设置为延迟实例化的bean。 因此,如果Ioc容器在启动的时候创建了那些设置为延迟实例化的bean的实例,你也不要觉得奇怪,因为那些延迟初始化的bean可能在配置的某个地方被注入到了一个非延迟初始化singleton bean里面。

结语

以上,本文就是关于Spring IoC 容器初始化的主要内容。

Spring IoC 的设计中,Bean定义的解析和Bean的依赖注入,是两个独立的过程,前面所有内容讲的就是IoC容器的初始化,资源定位、载入以及解析BeanDefinition并且注册。

最后一步的实例化所有单例,引入了 getBean() 方法,这就是Spring IoC 依赖注入的入口。也是下节源码解读的主要内容。

另外说一句,上面的源码解析,肯定不会是完备的,只是提取了我认为重要的东西。

如有疏漏,敬请谅解和自己查阅相关资料学习。如果错误,敬请指正!

本文由博客一文多发平台 OpenWrite 发布!

原文  https://segmentfault.com/a/1190000020696791
正文到此结束
Loading...