一.Spring Ioc 高级实现ApplicationContext的运行分析
ApplicationContext 这个Ioc的实现通常是在web应用中出现的,也是我们最常用的方式。启动项目,就开始初始化这个容器了。
Ioc容器的实现,都是通过三个步骤:定位资源文件,解析资源文件,对容器进行一些初始化操作。 前面对XmlBeanFactory的分析,只做到了前两步。
1.1 定位资源文件
// 这行代码,不会显示调用,在web项目启动的时候,通过在监听器中调用这行代码。
ApplicationContext beanFactory = new ClassPathXmlApplicationContext("spring/springmvc.xml");
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
// 直接调用重载的方法
this(new String[]{configLocation}, true, (ApplicationContext)null);
}
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
//存储Springmvc.xml 路径
this.setConfigLocations(configLocations);
if (refresh) {
// 初始化的时候refresh==true,核心逻辑的开始
this.refresh();
}
}
上面的代码说明,主要是获取到所有Spring相关的xml文件。例如ApplicationContext.xml 和 SpringMvc.xml 等。
// AbstractRefreshableConfigApplicationContext 类
public void setConfigLocations(String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for(int i = 0; i < locations.length; ++i) {
// 把xml路径放入到 String[] configLocations 中,支持多个配置文件以数组方式同时传入。
this.configLocations[i] = this.resolvePath(locations[i]).trim();
}
} else {
this.configLocations = null;
}
}
1.2 资源解析和对容器进行一些初始化操作
refresh()方法是包括了ApplicationContext 容器的全部操作
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
// 准备刷新上下文环境
this.prepareRefresh();
/* 加载BeanFactory,ApplicationContext是对BeanFactory功能的扩展,这个方法就是用来获取BeanFactory */
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//为BeanFactory配置容器特性,例如类加载器、事件处理器等
this.prepareBeanFactory(beanFactory);
try {
// 注册后处理BeanFactoryPostPorcessor
this.postProcessBeanFactory(beanFactory);
//调用BeanFactoryPostPorcessor this.invokeBeanFactoryPostProcessors(beanFactory);
//为BeanFactory注册BeanPost事件处理器.
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
// 为了管理容器注册一些监听器
this.registerListeners();
//这是对BeanDefinition 进行实例化的方法。
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
}
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
refresh()方法主要分两部分:
- 资源的解析:
// 准备刷新上下文环境
this.prepareRefresh();
/* 加载BeanFactory,ApplicationContext是对BeanFactory功能的扩展,这个方法就是用来获取BeanFactory */
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
经过上面两个方法,其实已经完成了前面XmlBeanFactory的所有功能了。
下面的方法,就是对容器进行功能的扩展和实例化所有的非懒加载的Bean了。
- 容器功能扩展和初始化
//为BeanFactory配置容器特性,例如类加载器、事件处理器等
this.prepareBeanFactory(beanFactory);
try {
// 注册后处理BeanFactoryPostPorcessor
this.postProcessBeanFactory(beanFactory);
//调用BeanFactoryPostPorcessor this.invokeBeanFactoryPostProcessors(beanFactory);
//为BeanFactory注册BeanPostPorcessor事件处理器.
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
// 为了管理容器注册一些监听器
this.registerListeners();
//这是对BeanDefinition 进行实例化的方法。
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
}
1.2.1 资源解析得到Ioc容器
// 实际这一段并没有做任何事,主要是为了扩展用的,spring本身并没有做任何事情
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (this.logger.isInfoEnabled()) {
this.logger.info("Refreshing " + this);
}
// 留给子类覆盖
this.initPropertySources();
// 验证需要的属性文件是否都已经放入环境中
this.getEnvironment().validateRequiredProperties();
this.earlyApplicationEvents = new LinkedHashSet();
}
obtainFreshBeanFactory()具体实现 AbstractApplicationContext类
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 调用相同类下的 refreshBeanFactory()方法
this.refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
refreshBeanFanctory() 在 AbstractRefreshableApplicationContext类中
protected final void refreshBeanFactory() throws BeansException {
// 判断是否有BeanFactory,初始化的时候,是没有的,false
if (this.hasBeanFactory()) {
this.destroyBeans();
this.closeBeanFactory();
}
try {
// 创建DefaultListableBeanFactory,
// new DefaultListableBeanFactory(this.getInternalParentBeanFactory());
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
beanFactory.setSerializationId(this.getId());
// 定制BeanFactory
this.customizeBeanFactory(beanFactory);
// 初始化 DocumetReader ,并进行XML文件读取及解析
// 这里就和XmlBeanFactory中一样了。
this.loadBeanDefinitions(beanFactory);
Object var2 = this.beanFactoryMonitor;
synchronized(this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException var5) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
}
}
初始化 DocumetReader ,并进行XML文件读取及解析 在AbstractXmlApplicationContext类
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 初始化BeanFactoryReader ,实际上就是加如一个验证位
this.initBeanDefinitionReader(beanDefinitionReader);
// 这里XmlBeanFactory创建时一样,通过一个XmlBeanDefinitionReader来读取Xml
this.loadBeanDefinitions(beanDefinitionReader);
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 检查ClassPathXmlApplicationContext中的 Resource[] configResources; 是否有资源,有就加载。
Resource[] configResources = this.getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
/* 检查AbstractRefreshableConfigApplicationContext中的String[] configLocations 中是否有资源 前面在 this.setConfigLocations(configLocations); 中我们把传入的 spring\mvc.xml 路径存入进去了。 */
String[] configLocations = this.getConfigLocations();
if (configLocations != null) {
// 根据路径加载 BeanDefinition 到 DefaultListableBeanFactory中去了,
// 具体实现参考 XmlBeanFactory的初始化
reader.loadBeanDefinitions(configLocations);
}
}
1.2.2 对Ioc容器进行功能扩展
在这之前,已经完成了对配置的解析。 ApplicationContext的功能扩展正式展开。
//为BeanFactory配置容器特性,例如类加载器、事件处理器等 this.prepareBeanFactory(beanFactory); try { // 注册后处理BeanFactoryPostPorcessor this.postProcessBeanFactory(beanFactory); //调用BeanFactoryPostPorcessor this.invokeBeanFactoryPostProcessors(beanFactory); //为BeanFactory注册BeanPostPorcessor事件处理器. this.registerBeanPostProcessors(beanFactory); this.initMessageSource(); this.initApplicationEventMulticaster(); this.onRefresh(); // 为了管理容器注册一些监听器 this.registerListeners(); //这是对BeanDefinition 进行实例化的方法。(重点) this.finishBeanFactoryInitialization(beanFactory); this.finishRefresh(); }
prepareBeanFactory() 在 AbstractApplicationContext
这个方法主要是对容器进行一些扩展。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 设置beanFactory的classLoader为当前context的classLoader
beanFactory.setBeanClassLoader(this.getClassLoader());
// 设置beanFactory的表达式语言
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
/* 增加对属性编辑器的支持,例如在SpringDI注入的时候,可以把普通属性注入进来,但是像Date类型就无法识别, 就需要这个转换了,不过一般时间 */
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));
// 添加BeanPostProcessor ,添加ApplicationContextAwareProcessor处理器
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.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 可以看到有很多addBeanPostProcessor
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// 增加对AspectJ的支持
if (beanFactory.containsBean("loadTimeWeaver")) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 添加默认的系统环境bean
if (!beanFactory.containsLocalBean("environment")) {
beanFactory.registerSingleton("environment", this.getEnvironment());
}
if (!beanFactory.containsLocalBean("systemProperties")) {
beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean("systemEnvironment")) {
beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());
}
}
下面两个方法,主要是向容器中添加BeanFactoryPostPorcessor
和调用其中的方法。在运行过程中,所有的 BeanFactoryPostPorcessor实现类 的后置方法在 Ioc 容器生成后,执行。
this.postProcessBeanFactory(beanFactory);
//调用BeanFactoryPostPorcessor this.invokeBeanFactoryPostProcessors(beanFactory);
下面的方法,是添加注册一些BeanPostProcessor,主要分两类:
- 一类是实现了BeanPostProcessor接口的类,它的作用是Bean对象再属性注入完成后,执行init()初始化方法的前后,进行拦截执行前置方法和后置方法。
- 一类是继承了了InstantiationAwareBeanPostProcessorAdapter 类,它的作用是Bean对象实例化,还没有属性注入前, 在实例化前后进行拦截。
具体可以看Spring初始化Ioc源码分析以及Aop原理分析(一) 中的分析
下面来分析是怎么注册 BeanPostProcessor 的
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new PostProcessorRegistrationDelegate.BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// 使用priorityOrderedPostProcessors 保证顺序。
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList();
List<BeanPostProcessor> internalPostProcessors = new ArrayList();
List<String> orderedPostProcessorNames = new ArrayList();
List<String> nonOrderedPostProcessorNames = new ArrayList();
String[] var8 = postProcessorNames;
int var9 = postProcessorNames.length;
String ppName;
BeanPostProcessor pp;
for(int var10 = 0; var10 < var9; ++var10) {
ppName = var8[var10];
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// 这里可以看出,已经对BeanPostProcessor实例化了。
pp = (BeanPostProcessor)beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
} else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
} else {
nonOrderedPostProcessorNames.add(ppName);
}
}
...
}
上面的方法,非常复杂,但核心思想就是,把BeanPostProcessor类的BeanDefinition给实例化成真正的对象,存储在容器中,供后面普通类初始化的时候去使用。
接下来的方法就是重点了
// 初始化所有剩下的非延迟加载类。
finishBeanFactoryInitialization(beanFactory)
前面也讲到了 ApplicationContext相对于XmlBeanFactory的区别就在于ApplicationContext会在初始化容器的时候,把bean顺带也加载了,而XmlBeanFactory不会,只有用到的时候才会加载。 具体来分析这个方法
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
......
beanFactory.setTempClassLoader((ClassLoader)null);
beanFactory.freezeConfiguration();
// 实例化对象的方法
beanFactory.preInstantiateSingletons();
}
实际加载bean的方法, 在 DefaulistableBeanFactory中。 这里和XmlBeanFactory一样,
// 通过getBean(beanName) 来实例化bean。
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Pre-instantiating singletons in " + this);
}
// 获取beanDefinitionNames 中 所有的beanName,为初始化准备
List<String> beanNames = new ArrayList(this.beanDefinitionNames);
Iterator var2 = beanNames.iterator();
.....
// 如果是FactoryBean,那就得到这个对象。
if (this.isFactoryBean(beanName)) {
final FactoryBean<?> factory = (FactoryBean)this.getBean("&" + beanName);
boolean isEagerInit;
...... // 这其中都是一堆的判断
if (isEagerInit) {
this.getBean(beanName);
}
} else {
// 前面都是各种判断,这里才是真正的实例化bean 的地方。
this.getBean(beanName);
}
}
}
}
通过这个方法,最后,还是通过getBean(beanName)去实例化对象,在Bean的生命周期那里已经对此进行分析了。