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如下:
- 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的结构下:
注册触发钩子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的大致的逻辑,如下:
再来看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