Spring的IOC容器在实现控制反转和依赖注入的过程,可以划分为两个阶段

  • 容器启动阶段
  • Bean实例化阶段
     

本文主要从这两个角度来解析源码的执行流程。

我们知道启动容器阶段会创建beanFactory,同时会将spring.xml中定义的beanDefinition注册到beanFactory中,or 在解析xml的过程中会找到对应标签的解析器(比如component-scan会触发Component扫描解析器),将扫描到的beanDefinition注册到beanFactory中,同时实例化钩子函数

(主要分为两块BeanFactoryPostProcessor 和BeanPostProcessor ),其中BeanFactoryPostProcessor在启动阶段会被触发,BeanPostProcessor 是在实例化Bean的阶段会被触发。

在Bean的实例化阶段,主要是根据beanDefinition来实例化,首先是构造函数,是否通过constructor-arg指定了有参构造函数,如果没有指定的话,则使用无参构造函数,其次给属性设置,对于通过注解注入的属性通过BeanPostProcessor钩子函数的方式来注入。

下面以这段代码为例,来解析源码的启动and实例化流程:

1public class TestMain {
2    public static void main(String[] args){
3        ClassPathXmlApplicationContext applicationContext = 
4                    new ClassPathXmlApplicationContext("spring.xml");
5        User user = (User) applicationContext.getBean("user");
6        System.out.println(user);
7    }
8}

spring.xml如下:

1    <!--<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">-->
 2        <!--<property name="ignoreUnresolvablePlaceholders" value="true" />-->
 3        <!--<property name="locations">-->
 4            <!--<list>-->
 5                <!--<value>classpath:config.properties</value>-->
 6            <!--</list>-->
 7        <!--</property>-->
 8    <!--</bean>-->
 9
10    <bean id="user" class="com.mian.User">
11        <constructor-arg name="name" value="${mian.name}"></constructor-arg>
12        <constructor-arg name="age" value="18"></constructor-arg>
13        <property name="hobby" ref="hobby"/>
14    </bean>
15
16    <context:property-placeholder location="classpath:config.properties"/>
17
18    <context:component-scan base-package="com.mian" />

先来看一下整体的结构图(注意实际的情况比这个复杂很多),只列出了需要说明的类。
图如下:

为什么 在容器里 启动进程 会把其他容器里的进程挤掉 容器启动非常快_实例化

图中分为两块:

  • 左边是beanFactory相关,主要是将beanDefinition注册到beanFactory中以及根据beanName来创建/获取Bean实例。基于安全的角度,获取beanDefinition相关的方法,不希望暴露给用户,所以增加了ApplicationContext,通过组合的方式只暴露了getBean方法。
  • 右边一块ApplicationContext
    ApplicationContext这里有两种方式FileSystem和ClassPath
    将共通的代码抽出成
    AbstractXmlApplicationContext
    (通过XmlBeanDefinitionReader组件将配置文件构建成BeanDefinition),其中启动容器和创建实例的代码在AbsractApplicationContext中。

容器启动

AbstractApplicationContext中的refresh方法(ClassPathXmlApplicationContext构造函数中调用):

1    @Override
 2    public void refresh() throws BeansException, IllegalStateException {
 3        synchronized (this.startupShutdownMonitor) {
 4            // Prepare this context for refreshing.
 5            // ① 记录启动时间,给子类留了initPropertySources的可覆盖方法,
 6            // 同时检查标记为必须的properties
 7            prepareRefresh();
 8
 9            // Tell the subclass to refresh the internal bean factory.
10            // ② 创建beanFactory,
11            // 重点是通过XmlBeanDefinitionReader将配置文件解析成BeanDefinition
12            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
13
14            // Prepare the bean factory for use in this context.
15            // ③ 给beanFactory设置一些属性比如classLoader,增加一些默认的钩子函数等
16            prepareBeanFactory(beanFactory);
17
18            try {
19                // Allows post-processing of the bean factory in context subclasses.
20                // ④ 给子类留下一个可覆盖的方法,默认是什么都不做
21                postProcessBeanFactory(beanFactory);
22
23                // Invoke factory processors registered as beans in the context.
24                // ⑤ 注册BeanFactoryPostProcessor到beanFactory中,并触发方法
25                invokeBeanFactoryPostProcessors(beanFactory);
26
27                // Register bean processors that intercept bean creation.
28                // ⑥ 注册BeanPostProcessor到beanFactory中,注意在创建实例的时候触发
29                registerBeanPostProcessors(beanFactory);
30
31                // Initialize message source for this context.
32                // ⑦ 注册messageSource
33                initMessageSource();
34
35                // Initialize event multicaster for this context.
36                // ⑧ 注册广播器
37                initApplicationEventMulticaster();
38
39                // Initialize other special beans in specific context subclasses.
40                // ⑨ 留给子类可覆盖的方法,默认是什么都不做
41                onRefresh();
42
43                // Check for listener beans and register them.
44                // ⑩ 给广播类添加listeners
45                registerListeners();
46
47                // Instantiate all remaining (non-lazy-init) singletons.
48                // 11. 添加字符串的解析器的${key:value},
49                // 将beanDefinitions中但单例的不是懒加载的实例实例化
50                finishBeanFactoryInitialization(beanFactory);
51
52                // Last step: publish corresponding event.
53                // 12. 启动所有实现了Lifecycle接口的类,同时发布事件
54                finishRefresh();
55            }
56
57            catch (BeansException ex) {
58            // 代码略
59            }
60
61            finally {
62            // 代码略  
63            }
64        }
65    }

代码解析:
注意上面容器启动的步骤,其中我们重点看以下几个动作:

② 通过XmlBeanDefinitionReader组件读spring.xml来创建BeanDefinition注册到beanFactory中

⑤ 注册BeanFactoryPostProcessor到beanFactory中,主要介绍PropertyPlaceholderConfigurer(将配置文件value中的${key:defalut}用配置的value来代替)

⑥ 注册BeanPostPostProessor到beanFactory中,在实例化的时候才会被触发,主要介绍AutowiredAnnotationBeanPostProcessor(被@Autowired @Value注解的属性用真正的实例or值注入)

 

⑪ 这里注意下在容器启动阶段,会将BeanDefinition中不是abstract是单例的不是懒加载的,实例化注册到beanFactory,之后直接可以从单例容器中获取。

加载bean定义-loadBeanDefinitions

1    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
 2        // Create a new XmlBeanDefinitionReader for the given BeanFactory.
 3        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
 4        // Configure the bean definition reader with this context's
 5        // resource loading environment.
 6        beanDefinitionReader.setEnvironment(this.getEnvironment());
 7        beanDefinitionReader.setResourceLoader(this);
 8        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
 9
10        // Allow a subclass to provide custom initialization of the reader,
11        // then proceed with actually loading the bean definitions.
12        initBeanDefinitionReader(beanDefinitionReader);
13        loadBeanDefinitions(beanDefinitionReader);
14    }

代码解析:

通过组件XmlBeanDefinitionReader将解读spring.xml配置文件,将beanDefinitions添加到beanFactory中的beanDefinitionMap中。

配置文件是在ClassPathXmlApplicationContext创建的时候已经指定了。

 

1// DefaultBeanDefinitionDocumentReader
 2protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
 3        if (delegate.isDefaultNamespace(root)) {
 4            NodeList nl = root.getChildNodes();
 5            for (int i = 0; i < nl.getLength(); i++) {
 6                Node node = nl.item(i);
 7                if (node instanceof Element) {
 8                    Element ele = (Element) node;
 9                    // 标签bean beans alias import走这条分支
10                    if (delegate.isDefaultNamespace(ele)) {
11                        parseDefaultElement(ele, delegate);
12                    }
13                    // component-scan annotation-config property-placeholder标签走这条分支
14                    else {
15                        delegate.parseCustomElement(ele);
16                    }
17                }
18            }
19        }
20        else {
21            delegate.parseCustomElement(root);
22        }
23    }

 

代码解析:

分为两条解析路径:

  • bean标签的如何解析成BeanDefinition,构建的BeanDefintion是怎样的?
  • component-scan|annotation-config|property-placeholder 这种标签是如何解析成BeanDefinition的。
直接在xml中定义的bean构建BeanDefintion
1    <bean id="user" class="com.mian.User">
2        <constructor-arg name="name" value="${mian.name}"></constructor-arg>
3        <constructor-arg name="age" value="18"></constructor-arg>
4        <property name="hobby" ref="hobby"/>
5    </bean>

构建的BeanDefinition如下:

为什么 在容器里 启动进程 会把其他容器里的进程挤掉 容器启动非常快_实例化_02

  • bean的id对应于beanFactory的beanDefinitionMap中
    存放BeanDefinition的Map容器的key
  • xml中的class对应了BeanDefinition中的beanClassName
  • constructor-arg对应BeanDefintion中的ConstructorArgumentValues,这个里面存放构造器的多个参数List。
  • property对应的是MutablePropertyValues(多个参数PropertyValue)
  • ValueHolder/PrpertyValue中的value存放的是RuntimeBeanReference
    还是TypedStringValue,取决于ref/value。前者说明是一个对象,注入的时候根据ref=beanName从beanFactory中获取即可,后者说明直接是值,依赖注入时转换成正确的类型即可。
component-scan这类标签构建的BeanDefinition
1\\ BeanDefinitionParserDelegate
2    public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
3        String namespaceUri = getNamespaceURI(ele);
4        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
5
6        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
7    }

代码解析:
spring的包META-INF/spring.handlers中定义了很多命名空间处理器。
根据命名空间找到对应的处理器,处理其中定义了各个标签对应的解析器。

比如ContextNamespaceHandler中的代码如下:

1public class ContextNamespaceHandler extends NamespaceHandlerSupport {
 2
 3    @Override
 4    public void init() {
 5        registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
 6        registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
 7        registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
 8        registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
 9        registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
10        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
11        registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
12        registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
13    }
14}

ComponentScanBeanDefinitionParser解析器中,

  • 负责扫描指定的报名
    将target中的类信息解析ScannedGenericBeanDefinition。
  • 默认注册一些BeanPostProcessor到beanFactory中 (annotation-config的标签默认也是会注册这些钩子post-processors)。

ConfigurationClassPostProcessor
AutowiredAnnotationBeanPostProcessor
RequiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor

ScannedGenericBeanDefinition的结构下:

为什么 在容器里 启动进程 会把其他容器里的进程挤掉 容器启动非常快_实例化_03

注册触发钩子invokeBeanFactoryPostProcessors

这里将钩子BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor的实例注册到beanFactory中。
来源主要是两方面:
一、开发者自定义通过addBeanFactoryPostProcessor加入到beanFactory中的beanFactoryPostProcessor钩子;
二、前面已经根据定义加载完毕beanDefintion,beanDefinition中的类型是beanFactoryPostProcessor的钩子
根据PriorityOrdered,Ordered,nonOrder顺序来加载并且触发以下两个方法:

1public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
2    void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
3}
4
5public interface BeanFactoryPostProcessor {
6    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
7}
介绍一种具体的钩子PropertyPlaceholderConfigurer

这个钩子的作用是:
1.读取指定的配置文件,解析成key-value对
2.遍历beanFactory中的所有beanDefinitions,检查以下各项,如果出现${key:default},则用配置文件中的value来代替。(注意-这里仅仅是更新的beanDefinition中value,而非实例化对象中的value)

1// 检查的各项 BeanDefinitionVisitor
 2    public void visitBeanDefinition(BeanDefinition beanDefinition) {
 3        visitParentName(beanDefinition);
 4        visitBeanClassName(beanDefinition);
 5        visitFactoryBeanName(beanDefinition);
 6        visitFactoryMethodName(beanDefinition);
 7        visitScope(beanDefinition);
 8        visitPropertyValues(beanDefinition.getPropertyValues());
 9        ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues();
10        visitIndexedArgumentValues(cas.getIndexedArgumentValues());
11        visitGenericArgumentValues(cas.getGenericArgumentValues());
12    }

加载此钩子的方式有两种:
一、在spring.xml的配置文件中定义如下,解析bean标签的时候此beanDefinition自然会被加入到beanFactory中

1<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
2        <property name="ignoreUnresolvablePlaceholders" value="true" />
3        <property name="locations">
4            <list>
5                <value>classpath:config.properties</value>
6            </list>
7        </property>
8    </bean>

二、在spring.xml的配置文件中定义如下,由前面的内容可知最终会

通过PropertyPlaceholderBeanDefinitionParser将PropertySourcesPlaceholderConfigurer的beanDefinition加载进beanFactory中

1<context:property-placeholder location="classpath:config.properties"/>

注册钩子registerBeanPostProcessors

将钩子的实例BeanPostProcessor注册到beanFactory中。
根据PriorityOrdered,Ordered,nonOrder顺序来加载(仅加载不触发)。

介绍一种具体的钩子AutowiredAnnotationBeanPostProcessor
1// AutowiredAnnotationBeanPostProcessor
 2    @Override
 3    public PropertyValues postProcessPropertyValues(
 4            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
 5
 6        InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
 7        try {
 8            metadata.inject(bean, beanName, pvs);
 9        }
10        catch (BeanCreationException ex) {
11            throw ex;
12        }
13        catch (Throwable ex) {
14            throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
15        }
16        return pvs;
17    }

 

代码解析:

扫描正在创建的bean的beanDefinition,将其中被@Value和@Autowired注解的Field和Method过滤出来,对通过反射来实行注入。
比如被@Autowird注解的field,通过从beanFactory中根据类型拿到对象实例,然后反射注入到field中。
被@Value注解的field,会使用字符串分解器用真正的值来注入。(容器启动会加载放置StrigValueResolver,PropertyPlaceholderConfigurer如果被加载会将过程中生成的字符串分解器存储起来)。

加载此钩子的方式:
在spring.xml的配置文件中定义如下,由前面的内容可知最终会通过AnnotationConfigBeanDefinitionParser或者ComponentScanBeanDefinitionParser解析器来加载这些钩子。

1<context:component-scan base-package="com.mian"  />

或者

1<context:annotation-config/>

Bean实例化

代码详见AbstractBeanFactory中的doGetBean以及AbstractAutowireCapableBeanFactory中的createBean

先来看doGetBean的大致的逻辑,如下:

为什么 在容器里 启动进程 会把其他容器里的进程挤掉 容器启动非常快_spring_04

再来看createBean中的逻辑,如下:
一、执行钩子InstantiationAwareBeanPostProcessor中的postProcessBeforeInstantiation;
如果不为空的话,则执行钩子BeanPostProcessor中的postProcessAfterInitialization。
(官方给的完美的解释:Give BeanPostProcessors a chance to return a proxy instead of the target bean instance)
二、createBeanInstance根据构造函数创建实例
beanDefintion中有constructorArgumentValues的场合,则选择合适(参数个数相同+参数类型匹配)的构造函数来创建一个实例。
无constructorArgumentValues,则通过无参构造函数创建一个实例。(比如扫描类得到的beanDefintion)
三、执行钩子函数MergedBeanDefinitionPostProcessor中的postProcessMergedBeanDefinition。
四、执行钩子函数InstantiationAwareBeanPostProcessor中的postProcessAfterInstantiation。
五、自动装配(bean的定义中定义了autowire="byName or byType or constructor")则执行自动装配。(默认情况下 default-autowire属性被设置为none, 标记所有bean都不适用自动装配,除非bean上配置了autowire属性。事实上,spring是不推荐自动装配的,最大的缺点在于不确定性,除非你对整个spring应用中的所有bean的情况都了如指掌,不然随着bean的增多和关系复杂度的上升,情况会变得很糟糕。)
六、执行钩子函数InstantiationAwareBeanPostProcessor中的postProcessPropertyValues。
比如我们上面介绍到的AutowiredAnnotationBeanPostProcessor(来注入@Value和@Autowired注解的field和method)
七、解析其中的BeanDefinition中的PropertyValue,注入创建的实例中。
比如spring.xml定义bean时用到的property。
八、给实现了Aware接口一些对象设置beanName类似这种操作
九、执行钩子函数BeanPostProcessor的postProcessBeforeInitialization
执行开发者自定义的init方法,之后执行钩子函数BeanPostProcessor的postProcessAfterInitialization。
十、registerDisposableBeanIfNecessary