文章目录
为什么要看Spring源码
- 解决使用框架时遇到的问题
- 深入理解底层原理,帮助更好的使用框架
- 深入理解面向对象思想和深入理解设计模式
- 高级程序员的常见面试点
如何看源码
- 确定主线,即想看那个流程的源码
- 找到流程入口
- 参考相关文档
- 寻找源代码规律
Spring中的IoC容器
在Spring中,有两种主要的容器类型,一种是BeanFactory,一种是ApplicationContext。其中BeanFactory是底层的容器实现,提供了IoC容器的基础功能,而ApplicationContext是一种应用级的容器,除了基础功能外还提供了更加丰富的功能,例如:
- 支持不同的信息源
- 支持事件发布
- 在ApplicationContext中提供附加服务
BeanFactory
BeanFactory是Spring中对IoC容器的核心抽象,在BeanFactory中定义了IoC容器的核心方法
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);
从接口中的方法签名可以很清楚的看到,BeanFactory提供了作为容器的基本功能。
基于BeanFactory,Spring提供了一系列的子接口即实现类来丰富BeanFactory,使其成为一个强大的IoC容器。BeanFactory的主体结构如下图所示:
Spring源码乍看给人一种很复杂的感觉,但如果把主体结构抽取出来,就可以很清楚的看到它的轮廓。
从图中可以看出,接口层主要包含了四个层次,从上到下依次是一个不断丰富功能的过程。
首先是BeanFactory,这是Spring IoC容器的顶级接口,上面已经介绍过。
往下走,分别是三个平级的接口,分别是ListableBeanFactory/AutowireCapableBeanFactory/HierachialBeanFactory,这三个接口都对BeanFactory进行了扩展。从名称可以比较明显的看出这几个接口扩展的方面。
ListableBeanFactory
boolean containsBeanDefinition(String beanName);
int getBeanDefinitionCount();
String[] getBeanDefinitionNames();
String[] getBeanNamesForType(ResolvableType type);
String[] getBeanNamesForType(Class<?> type);
String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);
<T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException;
<T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
throws BeansException;
String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);
Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
<A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
throws NoSuchBeanDefinitionException;
从接口签名中可以看出,ListablebeanFactory提供了Bean枚举相关的功能,如获取所有bean的名称及bean的总数量,获取bean名称和bean的映射等。
第二个接口是AutowireCapableBeanFactory,这个接口在BeanFactory的基础上扩展了自动装配的功能,例如创建Bean/自动配置bean/解析依赖以及与bean生命周期相关的功能。
代码略。
第三个接口是HieracicalBeanFactory,这个接口同样扩展子BeanFactory,它提供了在容器存在父子关系场景下与容器继承相关的操作。例如WebApplicationContext及ApplicationContext。
代码略。
至此,第二层继承接口就完事了。下面就是ConfigurablebeanFactory这个接口,这个接口继承自HieracicalBeanFactory,同时又扩展了SingletonBeanFactory,也就是与单例模式的Bean注册相关的功能,之所以这么做,个人理解单例模式是bean最常见的形式,将其注册能力加到稍顶级的接口中,有利于规范下层实现的行为。
代码略。
ConfigurableListableBeanFactory是第三层接口,这个接口同时继承了ListableBeanFactory
,AutowrieCapablebeanFactory
和ConfigurableBeanFactory
这三个接口,可以把它理解为spring中常用容器的顶级接口,它定义了一个功能完善的IoC容器的几乎所有行为。
代码略。
至此,BeanFactory体系的主体框架就看完了。
BeanDefinition
BeanDefinition是spring中对bean及bean依赖关系的抽象,如果把spring比做一个制造并管理bean的工厂的话,那BeanDefinition就是创造bean的原材料。
在spring启动过程中,spring会解析配置文件或配置类,将对应的bean定义解析成BeanDefinition并注册到spring容器中,在后续,spring会根据这些具体的BeanDefinition对象来创建并初始化这些bean。
BeanDefinition的继承结构如下:
Spring容器的初始化流程
由于我们在日常开发中经常使用的IoC容器是ApplicationContext,而不是更加底层的BeanFactory,所以在分析Spring容器初始化时,就以ApplicationContext为例,下面是ApplicationContext的体系结构
IoC容器的使用
由于在日常开发中,最常见的是ClassPathXmlApplicationContext,所以就以此为例来分析。首先看一下在日常开发中基本的使用方式。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
ApplicationContext ctx = new ClasspPthXmlApplicationContext("spring.xml");
容器初始化入口
ClassPathXmlApplicationContext.java
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
AbstractApplicationContext.java
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//Step1: 刷新预处理
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//Step2:创建IoC容器,解析xml,注册BeanDefinition
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//Step3:对IoC容器进行预处理
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//Step4:
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//Step5:调用BeanFactoryPostProcessor后置处理器对BeanDefinition进行处理
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//Step6:注册BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//Step7:初始化消息源(国际化)
initMessageSource();
// Initialize event multicaster for this context.
//Step8:初始化应用事件广播
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//Step9:初始化一些特殊的bean
onRefresh();
// Check for listener beans and register them.
//Step10:注册监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//Step11:实例话单例Bean,Bean的依赖注入和AOP都发生在这一步
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//Step12:完成,发布事件
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.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
在分析源码前,要先明确一下spring容器初始化的核心流程:
- 创建容器
- 加载配置资源文件
- 解析并注册BeanDefinition
- 完成bean的创建与初始化
这四个步骤对应到上面的refresh方法中,其中前三步是在step2中完成,第四步主要是在step11中完成。
解析&注册BeanDefinition
1.AbstractApplicationContext.java
/**
a)创建IoC容器
b)加载xml文件
c)解析并生成BeanDefinition,并注册到容器中
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
2.AbstractApplicationContext.java
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
/**
a)销毁存在的容器
b)创建BeanFactory
c)加载资源文件,并向容器中注册BeanDefinition
*/
refreshBeanFactory();
/**
返回上一步创建的BeanFactory
*/
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
3.AbstractRefreshableApplicationCon