Spring IOC源码跟踪记录

what is IOC?

IOC(Inversion of Control )控制反转,是Spring框架最重要的一个特性,提供了一个装载类的容器来为类之间进行解耦,并提供了一系列的扩展接口,使得开发者可以在bean的生命周期里自定义一些行为操作。

在没有IOC之前,类与类之间的耦合关系是这样的。这儿仅仅只有5个类,类之间的耦合关系就如此复杂,难以想象当类的数量随着业务发展而爆炸增多的时候,耦合关系是多么的糟糕。

img

在有了IOC之后,类与类之间的耦合关系是这样的。所有类都注册在IOC容器上,所有类只和IOC容器耦合,并且IOC容器为所有管理的类提供生命周期的管理。

img

how IOC do?

可以看出来IOC容器很像我们生活中的百货商场,我们需要什么东西都可以去百货商场买到,在没有百货商场以前我们买菜需要去菜市场,买手机需要去手机店,买电脑需要到电脑城……极大的方便了获取类的方式。接下来我通过Debug源码的方式来追一追整个IOC启动过程的步骤,希望能揭开这个“百货商场”的神秘面纱。

这是我们debug的入口,用的是最基础的XML解析的方式。

1
2
3
4
5
6
7
8
9
10
11
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
HelloService service = (HelloService) context.getBean("service");
service.say();
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent); //设置parent父容器
setConfigLocations(configLocations);//让ioc容器感知到xml配置文件
if (refresh) {
refresh();
}
}

做的第一步是super(parent),可以看出IOC容器是具备父子关系的,顺便提一下,这个特性在SpringMVC中体现出来了,SpringMVC的容器是 Spring容器的子容器,这样的结果就是Controller(SpringMVC容器中的Bean)可以调用Service(Spring容器中的类),而反过来则不行,这样一定程度保证了类之间的单向关系,以及调用方式不可逆,使得容器更加安全。

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 为刷新做好准备。
prepareRefresh();
// 告诉子类刷新内部bean工厂。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备beanfactory,为使用ioc容器做好准备
prepareBeanFactory(beanFactory);
try {
// 允许beanfactory准备好后做一些事情,扩展点
postProcessBeanFactory(beanFactory);
// 将bean注册在ioc容器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截bean创建的bean处理器。
registerBeanPostProcessors(beanFactory);
// 初始化上下文消息
initMessageSource();
// 为这个上下文初始化事件多播器。
initApplicationEventMulticaster();
// 初始化特定上下文子类中的其他特殊bean。
onRefresh();
// 检查listener类并注册它们
registerListeners();
// 实例化所有的lazy-init单例
finishBeanFactoryInitialization(beanFactory);
// 最后一步:发布相应的事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已经创建的单例
destroyBeans();
// 重置active的值
cancelRefresh(ex);
// 将异常传播给调用者
throw ex;
}
finally {
//清空一些元数据的内存,这些元数据生成了单例模式后就再也用不到了
resetCommonCaches();
}
}
}

这里是ioc容器的诞生点 createBeanFactory()

1
2
3
4
5
6
7
8
protected final void refreshBeanFactory() throws BeansException {
......

DefaultListableBeanFactory beanFactory = createBeanFactory();
......
loadBeanDefinitions(beanFactory);
......
}

再看看loadBeanDefinitions()方法 ,这里解释下什么是BeanDefinition (所有的Bean在Spring容器中的数据结构都是BeanDefinition,其中包含了跟这个bean相关的所有信息)beanDefinitionReader可以看做是一个IOC容器bean的生产者,可以从外部环境(xml,注解等)获取到bean的信息并装载进去,这个方法对beanDefinitionReader 设置了ResourceLoader,EnitityResolver等等对解析xml文件很重要的类,继续Debug看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}

ResourceLoader会去解析xml文件,将每个xml中的每个元素都解析然后返回一个DOM的文档树便于后续操作。

img

接着会执行prepareBeanFactory方法,这个方法类似一个制定ioc规则的方法,让哪些接口的bean不注册进去,哪些接口的bean注册进去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
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.
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.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

// Detect a LoadTimeWeaver and prepare for weaving, if found.
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.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}

之后会对实现了BeanFactoryPostProcessor接口的类处理,该扩展点允许在(容器已经初始完成,但是bean还没有初始化这部分时间进行扩展),体现了Spring的扩展性。

img

又看到了一个扩展点,BeanPostProcessor,该扩展点允许在bean 初始化之前或者之后的时候进行扩展

1
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

接下来回去预实例化没有设置lazy-init的类

1
beanFactory.preInstantiateSingletons();

进入这个方法体,在debug已经可以看到自己设置的bean的id值了

img

img

可以看到除了类之外还有scope,lazyInit,primary等属性

img

这儿走了一遍getBean的逻辑,不过因为没有初始化,去到的实例都是null,接着会标记即将创建的bean,并将其缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
标记已创建的(或即将创建的)指定bean。
这允许bean工厂优化其缓存重复。
创建指定的bean。
* @param beanName the name of the bean
*/
protected void markBeanAsCreated(String beanName) {
if (!this.alreadyCreated.contains(beanName)) {
synchronized (this.mergedBeanDefinitions) {
if (!this.alreadyCreated.contains(beanName)) {
// Let the bean definition get re-merged now that we're actually creating
// the bean... just in case some of its metadata changed in the meantime.
clearMergedBeanDefinition(beanName);
this.alreadyCreated.add(beanName);
}
}
}
}

马上进入实例化bean的代码,其中createBean()是重点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});

追了好几层终于看到,bean是通过反射实例化的。

1
Class<?> resolvedClass = ClassUtils.forName(className, classLoader);

如果是singleton,直接从map里面取,如果没有则通过反射生成,放进map中然后返回,如果是prototype则每次获取都会实例化,返回一个新的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

这就是缓存单例bean的map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
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);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

总结

ResourceLoader对xml文档树进行读取解析生成Resource文件,Resource文件封装了对xml文件的IO操作,然后BeanDefinitionReader会对Resource文件读取并生成BeanDefinition放在BeanDefinitionRegistry里面,过后beanFactoryPostProcesser会解析占位符,然后SimpleInstantiationStrategy会通过反射实例化,然后BeanWrapper会对非lazy-init的bean进行赋值,在getBean的时候IOC容器通过Map缓存的方式来达到单例的效果。

文章目录
  1. 1. what is IOC?
  2. 2. how IOC do?
  3. 3. 总结
|