Spring源码分析之ApplicationContext

2022/5/12 20:27:39

本文主要是介绍Spring源码分析之ApplicationContext,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

前言

通过前面的博客我们已经对Spring的IOC容器有了一定的了解,它的底层实现为DefaultListableBeanFactory,这是一个BeanFactory,
ApplicationContext在BeanFactory容器的基础上又增加了很多功能,如事件分发,国际化等。相关类图如下

可以看到ApplicationContext是BeanFactory的子接口,但是它没有自己实现这些方法,对于Bean的操作,都是委托给BeanFactory来处理的。
ApplicationContext有很多实现类,如支持XML配置的ClassPathXmlApplicationContext,支持注解配置的AnnotationConfigApplicationContext,
支持内嵌Tomcat和注解的AnnotationConfigServletWebServerApplicationContext(SpringBoot默认使用)。
这里我们以ClassPathXmlApplicationContext为例来分析,AnnotationConfigApplicationContext对于注解的处理额外做了很多工作,不利于分析流程。

简单使用

首先在classpath下创建一个XML配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="userService"
    class="com.imooc.sourcecode.java.spring.ioc.test4.TestXmlContext.UserService"/>
</beans>

使用ClassPathXmlApplicationContext来解析此配置文件

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestXmlContext {

  public static void main(String[] args) {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
    context.setConfigLocation("spring.xml");
    context.refresh();
    UserService userService = (UserService) context.getBean("userService");
    userService.userList();//userList
  }

  public static class UserService {

    public void userList() {
      System.out.println("userList");
    }
  }
}

使用方式很简单,但Spring内部帮我们做了很多工作。

源码分析

核心为refresh()方法,进入父类AbstractApplicationContext中

@Override
public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			//做一些准备工作,主要是environment对象的创建
			prepareRefresh();

			//创建DefaultListableBeanFactory容器,并从XML配置文件中加载BeanDefinition,注册到容器中
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			//配置BeanFactory,设置ClassLoader,设置SpringEL表达式解析器,向BeanFactory中添加特定的BeanPostProcessor
			prepareBeanFactory(beanFactory);

			try {
				//对beanFactory做一些处理,留给子类扩展
				postProcessBeanFactory(beanFactory);

				//从容器中获取所有类型为BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor的Bean,并执行他们的扩展方法
                                //这两个类是Spring提供的两种扩展
                                //ConfigurationClassPostProcessor(用来解析@Configuration类,注解自动扫描等)就是在这一步执行的
				invokeBeanFactoryPostProcessors(beanFactory);

				//从容器中获取所有类型为BeanPostProcessor的Bean,并设置到BeanFactory中(调用BeanFactory的addBeanPostProcessor()方法)
                                //最重要的AutowiredAnnotationBeanPostProcessor(处理@Autowired注解)就是在这添加的
				registerBeanPostProcessors(beanFactory);

				//初始化MessageSource,这是一个支持国际化的组件
				initMessageSource();

				//初始化事件分发器,默认类型为SimpleApplicationEventMulticaster,通过它我们可以实现事件的订阅和发布
				initApplicationEventMulticaster();

				//留给子类扩展,ServletWebServerApplicationContext(SpringBoot使用的是它的子类)在这一步创建了WebServer(默认是Tomcat),注意,还没启动
				onRefresh();

				//从容器中获取所有类型为ApplicationListener的Bean,并注册到事件分发器中
                                //SpringBoot会从spring.factories中获取配置的ApplicationListener列表,
                                //如ConfigFileApplicationListener(用来解析application.yml文件或application.properties文件)
				registerListeners();

				//实例化所有非懒加载的单例Bean,其实就是依次调用getBean(name)方法,BeanFactory会在第一次调用时创建Bean
				finishBeanFactoryInitialization(beanFactory);

				//实例化DefaultLifecycleProcessor对象(这是一个生命周期处理器),
                                //发布ContextRefreshedEvent事件(监听此事件的ApplicationListener都会处理)
                                //ServletWebServerApplicationContext(SpringBoot使用的是它的子类)在这一步启动WebServer(默认是Tomcat)
				finishRefresh();
			}

			catch (BeansException ex) {
				//如果抛出异常,销毁所有已经创建的Bean
				destroyBeans();

				//重置active标识
				cancelRefresh(ex);

				throw ex;
			}

			finally {
				//清空缓存,如反射的缓存
				resetCommonCaches();
			}
		}
	}

此方法执行完,我们的ApplicationContext对象可以算是初始化完成了,所有的非懒加载Bean也已经创建完成了。
上面的每一个方法实现都是比较复杂的,细节很多,这里我们再简单分析一下obtainFreshBeanFactory()方法。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
                //创建并初始化BeanFactory
		refreshBeanFactory();
		return getBeanFactory();
	}

继续跟进去refreshBeanFactory()方法,AbstractRefreshableApplicationContext类重写了此方法

@Override
protected final void refreshBeanFactory() throws BeansException {
                //如果已经创建过BeanFactory,销毁所有Bean
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
                        //创建一个新的beanFactory,可以看到实现为DefaultListableBeanFactory类型
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
                        //从XML配置文件中加载BeanDefinition
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
	}

分析总结

从上面的类图可以看到,ApplicationContext接口继承ApplicationEventPublisher(事件分发器),MessageSource(国际化相关),BeanFactory(IOC容器),
但ApplicationContext的实现类本身没有实现这些接口的方法,而是委托给对应的实现类,如事件分发委托给SimpleApplicationEventMulticaster,
国际化委托给ResourceBundleMessageSource(我们需要自己定义此Bean),IOC容器委托给DefaultListableBeanFactory。

@Override
public Object getBean(String name) throws BeansException {
		return getBeanFactory().getBean(name);
	}

以getBean()方法为例,可以看到确实是交给内部的BeanFactory来处理的。

关于国际化,可以查看Spring对国际化的支持 。

参考

Spring IOC 容器源码分析



这篇关于Spring源码分析之ApplicationContext的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程