一、容器简介
容器顾名思义就是用来装东西的,装的是什么?装的是 Bean。
Bean 是 Spring 的基本单位,在基于 Spring 的 Java EE 应用中,所有的组件都被当成 Bean 处理,包括数据源、Hibernate 的 SessionFactory、事务管理器等。在 Spring 中,Bean 是一个非常广义的概念,任何 Java 对象、Java 组件都被当成 Bean 处理。
那容器仅仅是用来保存 Bean 这么简单么?不是。
当我们需要使用某个 Bean 时,容器会自动帮我们创建,并在适当时销毁。还有一种情况,当某个 Bean 中需创建另一个 Bean 时,也就是 Bean 之间有依赖关系,这种依赖的 Bean 也是由容器自动创建。在外界有一个标准的名词,前者称呼为 IOC,也就是控制反转,后者称呼为 DI,也就是依赖注入。
IOC/DI
IOC (Inversion of Control) 控制反转:所谓控制反转,就是当我们需要某个 Bean 时,将 Bean 的名称告知容器,由容器去创建该 Bean,而不是我们手动 new 一个,这里 Bean 创建管理的控制权都交给了容器,所以这是一种控制权的反转。其通俗点讲就是需要什么东西让别人送过来,而不是自己去拿。
DI (Dependency Injection) 依赖注入:就是指当 A Bean 里面需创建 B Bean 时,会在创建 A Bean 的时候,自动将依赖的 B Bean 注入进去,其 B Bean 是被动接受注入而不是自己主动去找。换句话说就是指 A Bean 不是从容器中查找它依赖的 B Bean,而是在容器创建 A Bean 候主动将它依赖的 B Bean 注入给它。
IOC 和 DI 其实归根结底实现的功能是相同的,只是同样的功能站在不同的角度来阐述罢了,不过我们通常喜欢将这两个概念统称为 IOC。当然,在真实场景中,交由 Spring 容器创建的 Bean 泛指在应用程序中的表现层、业务层、持久层等各层对应的 Bean,如 Controller、Service 等;进行数据交互的模型,如 DTO、VO 等就不需交由 Spring 来创建。
所以,容器本质上可以也可以看作是 Bean 工厂,该工厂管理 Bean 的生命周期,以及 Bean 之间的依赖关系。外界也将 Spring 容器称为 IOC 容器。当然,这里容器仅仅是 Spring 的抽象概念,代码中将其具象化为 BeanFactory 或 ApplicationContext,容器功能也由具象化的类进行处理。
二、容器的结构
0、概述
容器的实现类并不是唯一的,Spring 框架提供了多个容器的实现,这些容器分为两套体系:一套是早期的 BeanFactory 体系;还有一套是现在常用的 ApplicationContext,也可称为应用上下文,它继承了 BeanFactory,它除了有 BeanFactory 的功能外
,还提供了其他服务,例如事务和 AOP 服务、国际化(il8n)的消息源以及应用程序事件处理等企业级的服务。
说到这,就不得不说 Spring 的两种配置方式,在早期都是 XML 配置文件的方式,而现在使用的是注解配置的方式。BeanFactory 体系的容器一般用来处理 XML 配置文件的方式,而 ApplicationContext 体系则都可以处理。
重点关注的实现类
BeanFactory
的DefaultListableBeanFactory
DefaultSingletonBeanRegistry
ClassPathXmlApplicationContext
:加载类路径下的配置文件,要求配置文件必须在类路径下。AnnotationConfigApplicationContext
:读取注解创建容器。FileSystemXmlApplicationContext
:加载磁盘任意路径下的配置文件(必须有访问权限)
SpringBoot Web 容器
SpringBoot 的 Web 容器底层的实现类是 AnnotationConfigServletWebServerApplicationContext
当调用 getBean()
方法时,实际是调用内部的成员变量 beanFactory
的 getBean()
方法
它的成员变量 singletonObjects
中存储着所有的单例 bean
((DefaultListableBeanFactory)(
(AnnotationConfigServletWebServerApplicationContext)applicationContext
).beanFactory).singletonObjects
1、BeanFactory
(1)概述
BeanFactory 是容器最基础的类,它定义了容器的基本功能规范:
public interface BeanFactory {
// 对 FactoryBean 的转义定义,因为如果使用 bean 的名字检索 FactoryBean 得到的对象是工厂生成的对象,
// 如果需要得到工厂本身,需要转义(FactoryBean 在后续会详细介绍)
String FACTORY_BEAN_PREFIX = "&";
// 根据 bean 的名字,获取在容器中 bean 实例
Object getBean(String name) throws BeansException;
//根据 bean 的名字和 Class 类型来得到 bean 实例,增加了类型安全验证机制。
<T> T getBean(String name, @Nullable 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;
// 提供对 bean 的检索,看看是否在容器有这个名字的 bean
boolean containsBean(String name);
// 根据 bean 名字,判断这个 bean 是不是单例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// 根据 bean 名字,判断这个 bean 是不是原型
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
// 根据 bean 名字,判断是否与指定的类型匹配
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
// 得到 bean 实例的 Class 类型
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
// 得到bean 的别名,如果根据别名检索,那么其原名也会被检索出来
String[] getAliases(String name);
}
在 BeanFactory 里只对容器的基本行为作了定义,其根本不关心你的 Bean 是如何定义怎样加载的。
正如我们只关心工厂里得到什么的产品对象,至于工厂是怎么生产这些对象的,这个基本的接口不关心。而要知道工厂是如何产生对象的,我们就需要看具体的容器了,也就是 BeanFactory 的子类。
BeanFactory 大致的继承关系如下:
BeanFactory
体系中常用的实现接口有:
ListableBeanFactory
:提供容器中 bean 迭代的功能。如返回所有 Bean 的名字、容器中 Bean 的数量等,实现Bean的list集合操作功能。HierarchicalBeanFactory
:提供父容器的访问功能,可通过 ConfigurableBeanFactory 的 setParentBeanFactory 方法设置父容器。AutowireCapableBeanFactory
:为 Spring 容器之外的 Bean ,也就是未交由 Spring 管理的 Bean ,提供依赖注入的功能(实现Bean的自动装配功能)。
以上三个是 BeanFactory
的直系亲属,这个三个直系亲属下面又派生了两个复杂的容器:
ConfigurableBeanFactory
:其继承了HierarchicalBeanFactory
和SingletonBeanRegistry
(单例bean的注册接口)这两个接口,其提供了很多方法,如:定义类加载器、类型转化、属性编辑器、注册依赖 Bean 、销毁 bean 等,且该接口被大多数的容器继承、实现。ConfigurableListableBeanFactory
:这个接口继承了 ListableBeanFactory、 AutowireCapableBeanFactory、ConfigurableBeanFactory,自身主要提供用于分析和修改 bean 定义以及预先实例化单例 Bean 的方法。综合接口。
最后是核心容器:
- DefaultListableBeanFactory:它实现了以上所有的接口,在
BeanFactory
体系中可以作为一个独立的容器使用。
其实以前常用的容器是 XmlBeanFactory ,它是 DefaultListableBeanFactory 的实现类,现已被废除。
但我们基本不单独使用 BeanFactory ,而是直接使用 ApplicationContext ,因为 ApplicationContext 包含了 BeanFactory。
(2)DefaultListableBeanFactory
BeanFactory
:表面上只有 getBean
等几个简单的方法,实际上控制反转、依赖注入、直至 Bean 的生命周期的各种功能,都是由他的实现类 DefaultListableBeanFactory
提供的。
DefaultListableBeanFactory
中单例 Bean 的管理则是由其父类 DefaultSingletonBeanRegistry
提供。DefaultSingletonBeanRegistry
中有三级缓存,用于解决循环依赖
DefaultListableBeanFactory 简单使用说明
a. beanFactory 不会做的事
1. 不会主动调用 BeanFactory 后处理器
2. 不会主动添加 Bean 后处理器
3. 不会主动初始化单例
4. 不会解析beanFactory 还不会解析 ${ } 与 #{ }
b. bean 后处理器会有排序的逻辑
public class TestBeanFactory {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// bean 的定义(class, scope, 初始化, 销毁)
AbstractBeanDefinition beanDefinition =
BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
// 注册 BeanDefinition 到容器中,参数1: beanDefinition对应生成的bean的名称;
beanFactory.registerBeanDefinition("config", beanDefinition);
// 给 BeanFactory 添加一些常用的后处理器,@Configuration、@Autowired。。。
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
/* ---------------------- beanFactory后置处理器 ------------------------ */
// BeanFactory 后处理器主要功能,补充了一些 bean 定义
// 获取 bean工厂所有的后置处理器,并执行
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
// 执行后置处理器
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
/* ---------------------- bean后置处理器 ------------------------ */
// Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
// 用于修改后置处理器的执行顺序
.sorted(beanFactory.getDependencyComparator())
.forEach(beanPostProcessor -> {
System.out.println(">>>>" + beanPostProcessor);
// 执行后置处理器
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
// DefaultListableBeanFactory中的单例bean默认是懒加载的,即第一次使用时才去创建对象
// 该语句作用是立刻创建所有单例bean
beanFactory.preInstantiateSingletons();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
// System.out.println(beanFactory.getBean(Bean1.class).getBean2());
System.out.println(beanFactory.getBean(Bean1.class).getInter());
}
@Configuration
static class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
@Bean
public Bean3 bean3() {
return new Bean3();
}
@Bean
public Bean4 bean4() {
return new Bean4();
}
}
interface Inter {
}
static class Bean3 implements Inter {
}
static class Bean4 implements Inter {
}
static class Bean1 {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
public Bean1() {
log.debug("构造 Bean1()");
}
@Autowired
private Bean2 bean2;
public Bean2 getBean2() {
return bean2;
}
@Autowired
@Resource(name = "bean4")
private Inter bean3;
public Inter getInter() {
return bean3;
}
}
static class Bean2 {
private static final Logger log = LoggerFactory.getLogger(Bean2.class);
public Bean2() {
log.debug("构造 Bean2()");
}
}
}
2、ApplicationContext
上面说过 ApplicationContext 是 BeanFactory 子类,它不仅包含 BeanFactory 所有功能,还对其进行了扩展,而我们喜欢将 ApplicationContext 称为应用上下文,因为容器只是它的基本功能。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
// 返回此应用程序上下文的唯一ID
@Nullable
String getId();
// 返回此上下文所属的应用程序名称
String getApplicationName();
// 返回应用上下文具像化的类名
String getDisplayName();
// 返回第一次加载此上下文时的时间戳
long getStartupDate();
// 获取父级应用上下文
@Nullable
ApplicationContext getParent();
// 将 AutowireCapableBeanFactory 接口暴露给外部使用
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
ApplicationContext 自身提供的方法非常简单,但它继承了六个接口,来扩展自身功能:
EnvironmentCapable
:获取 Environment。MessageSource
:支持国际化功能。ApplicationEventPublisher
:应用事件发布器,封装事件发布功能的接口。ResourcePatternResolver
:该接口继承至 ResourceLoader ,作用是加载多个 Resource。- ListableBeanFactory、HierarchicalBeanFactory:这是 BeanFactory 体系接口,分别提供 Bean 迭代和访问父容器的功能。
ApplicationContext 同样提供了非常多的实现类,其又可细分为两大类, ConfigurableApplicationContext 和 WebApplicationContext。
EnvironmentCapable
:获取环境变量或配置文件的属性
获取的环境变量键不区分大小写
// 获取环境变量的值
String javaHome = context.getEnvironment().getProperty("java_home");
// 获取配置文件的值
String port = context.getEnvironment().getProperty("server.port");
MessageSource
:国际化
https://www.jianshu.com/p/4d5f16f6ab82
ResourcePatternResolver
:加载资源
// 不带*:仅查找当前项目资源目录下的资源
Resource[] resources = context.getResources("classpath:application.yml");
// 带*:查找当前项目资源目录的资源,同时查找依赖的 jar 包资源目录的资源
Resource[] resources2 = context.getResources("classpath*:META-INF/spring.factories");
ApplicationEventPublisher
:事件的发布、监听
事件对象
/**
* 事件对象
* ApplicationEvent其实只是提供了序列化、时间戳、构造方法
*/
public class UserLoginEvent extends ApplicationEvent {
/**
* source 作用:
* 1、监听器source的类型用来分辨是否监听该事件、
* 2、事件发生时携带的参数(数据)
*/
public UserLoginEvent(Object source) {
super(source);
}
}
发布事件
// 任何对象都可作为事件
Order order = new Order("id", "name", "age");
context.publishEvent(order);
// 比较标准
context.publishEvent(new UserLoginEvent(order));
监听事件(仅监听对应的事件发布)
@Component
public class TestCompontent {
@EventListener
public void listener(Order order){
//Order(userId=id, orderId=name, goodId=age)
System.out.println(order);
}
@EventListener
public void listener(UserLoginEvent event){
System.out.println(event);
//Order(userId=id, orderId=name, goodId=age)
System.out.println(event.getSource());
}
}
有点像消息队列,多用于代码解耦
(1)常见实现类使用
public class A02 {
private static final Logger log = LoggerFactory.getLogger(A02.class);
public static void main(String[] args) {
testClassPathXmlApplicationContext();
// testFileSystemXmlApplicationContext();
// testAnnotationConfigApplicationContext();
// testAnnotationConfigServletWebServerApplicationContext();
}
// ⬇️较为经典的容器, 基于 classpath 下 xml 格式的配置文件来创建
private static void testClassPathXmlApplicationContext() {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("a02.xml");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
// ⬇️基于磁盘路径下 xml 格式的配置文件来创建
private static void testFileSystemXmlApplicationContext() {
FileSystemXmlApplicationContext context =
new FileSystemXmlApplicationContext(
"src\\main\\resources\\a02.xml");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
// ⬇️较为经典的容器, 基于 java 配置类来创建
private static void testAnnotationConfigApplicationContext() {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(Config.class);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
// ⬇️较为经典的容器, 基于 java 配置类来创建, 用于 web 环境
private static void testAnnotationConfigServletWebServerApplicationContext() {
AnnotationConfigServletWebServerApplicationContext context =
new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
}
@Configuration
static class WebConfig {
@Bean
public ServletWebServerFactory servletWebServerFactory(){
return new TomcatServletWebServerFactory();
}
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
@Bean
public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}
@Bean("/hello")
public Controller controller1() {
return (request, response) -> {
response.getWriter().print("hello");
return null;
};
}
}
@Configuration
static class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2(Bean1 bean1) {
Bean2 bean2 = new Bean2();
bean2.setBean1(bean1);
return bean2;
}
}
static class Bean1 {
}
static class Bean2 {
private Bean1 bean1;
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
public Bean1 getBean1() {
return bean1;
}
}
}
(2)ConfigurableApplicationContext
该接口是比较重要的一个接口,几乎所有的应用上下文都实现了该接口。该接口在ApplicationContext的基础上提供了配置应用上下文的能力,此外提供了生命周期的控制能力。
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
// 应用上下文配置时,这些符号用于分割多个配置路径
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
// BeanFactory中,ConversionService类所对应的bean的名字。如果没有此类的实例的话吗,则使用默认的转换规则
String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
//LoadTimeWaver类所对应的Bean在容器中的名字。如果提供了该实例,上下文会使用临时的 ClassLoader ,这样,LoadTimeWaver就可以使用bean确切的类型了
String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
// Environment 类在容器中实例的名字
String ENVIRONMENT_BEAN_NAME = "environment";
// System 系统变量在容器中对应的Bean的名字
String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
// System 环境变量在容器中对应的Bean的名字
String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";
// 设置容器的唯一ID
void setId(String id);
// 设置此容器的父容器
void setParent(@Nullable ApplicationContext parent);
// 设置容器的 Environment 变量
void setEnvironment(ConfigurableEnvironment environment);
// 以 ConfigurableEnvironment 的形式返回此容器的环境变量。以使用户更好的进行配置
@Override
ConfigurableEnvironment getEnvironment();
// 此方法一般在读取应用上下文配置的时候调用,用以向此容器中增加BeanFactoryPostProcessor。增加的Processor会在容器refresh的时候使用。
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
// 向容器增加一个 ApplicationListener,增加的 Listener 用于发布上下文事件,如 refresh 和 shutdown 等
void addApplicationListener(ApplicationListener<?> listener);
// 向容器中注入给定的 Protocol resolver
void addProtocolResolver(ProtocolResolver resolver);
// 这是初始化方法,因此如果调用此方法失败的情况下,要将其已经创建的 Bean 销毁。
// 换句话说,调用此方法以后,要么所有的Bean都实例化好了,要么就一个都没有实例化
void refresh() throws BeansException, IllegalStateException;
// 向JVM注册一个回调函数,用以在JVM关闭时,销毁此应用上下文
void registerShutdownHook();
// 关闭此应用上下文,释放其所占有的所有资源和锁。并销毁其所有创建好的 singleton Beans
@Override
void close();
// 检测此 FactoryBean 是否被启动过
boolean isActive();
// 返回此应用上下文的容器。
// 千万不要使用此方法来对 BeanFactory 生成的 Bean 做后置处理,因为单例 Bean 在此之前已经生成。
// 这种情况下应该使用 BeanFactoryPostProcessor 来在 Bean 生成之前对其进行处理
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
该接口下又有几个重要的实现类:
- AbstractApplicationContext:这是个抽象类,仅实现了公共的上下文特性。这个抽象类使用了模板方法设计模式,需要具体的实现类去实现这些抽象的方法。
- GenericApplicationContext:该类继承自 AbstractApplicationContext,是为通用目的设计的,它能加载各种配置文件,例如 xml,properties 等等。它的内部持有一个 DefaultListableBeanFactory 的实例,实现了 BeanDefinitionRegistry 接口,以便允许向其应用任何 bean 的定义的读取器。
- AnnotationConfigApplicationContext:该类继承自 GenericApplicationContext ,提供了注解配置(例如:@Configuration、@Component等)和类路径扫描(scan方法)的支持。
(3)WebApplicationContext
该接口是专门为 Web 应用准备的,其允许从相对于 Web 根目录的路径中装载配置文件完成初始化。
public interface WebApplicationContext extends ApplicationContext {
// 整个 Web 应用上下文是作为属性放置在 ServletContext 中的,该常量就是应用上下文在 ServletContext 属性列表中的 key
String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
// 定义了三个作用域的名称
String SCOPE_REQUEST = "request";
String SCOPE_SESSION = "session";
String SCOPE_APPLICATION = "application";
// 在工厂中的 bean 名称
String SERVLET_CONTEXT_BEAN_NAME = "servletContext";
// ServletContext 初始化参数名称
String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";
// 在工厂中 ServletContext 属性值环境bean的名称
String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";
// 用来获取 ServletContext 对象
@Nullable
ServletContext getServletContext();
}
该接口的核心实现类有:
- ConfigurableWebApplicationContext:该接口同时继承了 WebApplicationContext 和 ConfigurableApplicationContext,提供了 Web 应用上下文的可配置的能力。
- GenericWebApplicationContext:该类继承自 GenericApplicationContext,实现了 ConfigurableWebApplicationContext。
- XmlWebApplicationContext:该上下文是使用 Xml 配置文件的方式,不过是在 Web 环境中使用的。
- AnnotationConfigServletWebServerApplicationContext:该类是被 SpringBoot 扩展而来的,SpringBoot 使用的就是该上下文。
3、差异对比
从上面可以看出 BeanFactory 是 Sping 框架的基础接口,一般是面向 Spring 本身;而 ApplicationContext 是以 BeanFactory 为基础进行综合能力扩展,用于满足大型业务应用的创建, ApplicationContext 一般面向使用 Sping 框架的开发者。几乎所有的应用场合我们都是直接使用 ApplicationContet 而非底层的 BeanFactory。
下表列出了BeanFactory 和 ApplicationContext 接口和实现所提供的功能:
功能 / 特点 | BeanFactory | ApplicationContext |
---|---|---|
Bean 实例化/装配 | 有 | 有 |
BeanPostProcessor 自动注册 | 没有 | 有 |
BeanFactoryPostProcessor 自动注册 | 没有 | 有 |
MessageSource 便捷访问(针对i18n) | 没有 | 有 |
ApplicationEvent 发布 | 没有 | 有 |
两者还有一个区别是:
- ApplicationContext 在容器启动时,一次性创建了所有的 Bean。
- BeanFactory 在容器启动时,并未创建 Bean,直到第一次访问某个 Bean 时才创建目标 Bean。
三、Spring启动流程简述
1、首先会进行扫描,扫描得到所有的BeanDefinition对象,并存在一个Map中
2、然后饰选出非做加载的单例BeanDefnition进行创建Bean,对于多例Bean不需要在启动讨程中去进行创建,对于多例Bean会在每次获取Bean时利用BeanDefnition去创建
3、利用BeanDefinition创建Bean就是Bean的创建生命周期,这期间包括了合并BeanDefinion、推断构造方法、实例化、属性填充、初始化前、初始化、初始化后等步骤,其中AOP就是发生在初始化后这一步骤中
4、单例Bean创建完了之后,Spring会发布一个容器启动事件
5、Spring启动结束
6、在源码中会更复杂,比如源码中会提供一些模板方法,让子类来实现,比如源码中还涉及到一些BeanfactoryPostProcesor和BeanPostProcessor的注册,Spring的扫描就是通过BenaFactoryPostProcessor来实现的,依赖注入就是通过BeanPostProcessor来实现的
三、启动容器流程详解
1、测试代码
public static void main(String[] args) {
// 看 2
ApplicationContext applicationContext = new
ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person)applicationContext.getBean("person");
Rabbit rabbit = (Rabbit)applicationContext.getBean("rabbit");
System.out.println(person);
System.out.println(rabbit);
}
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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--注解的组件扫描-->
<context:component-scan base-package="com.rewind"/>
<bean id="rabbit" class="com.suger.Rabbit"/>
</beans>
2、调用构造方法
public class ClassPathXmlApplicationContext
extends AbstractXmlApplicationContext {
public ClassPathXmlApplicationContext(String configLocation)
throws BeansException {
this(new String[] {configLocation}, true, null);
}
/**
* 根据给定的父容器创建一个新的容器
* @param configLocations 配置文件路径数组
* @param refresh 是否自动刷新容器,加载所有的 bean 定义,并且创建所有的单例 bean
* 或者,在进一步配置上下文后手动调用refresh。
* @param parent the parent context
*/
public ClassPathXmlApplicationContext(
String[] configLocations,
boolean refresh,
@Nullable ApplicationContext parent) throws BeansException {
//设置父容器,并且将当前的环境变量和父容器的环境变量合并
super(parent);
// 设置配置文件路径
setConfigLocations(configLocations);
if (refresh) {
//刷新容器,加载所有的 bean 定义,并创建所有的单例bean
//看4
refresh();
}
}
}
3、刷新容器
3-1、refresh()
public abstract class AbstractApplicationContext
extends DefaultResourceLoader
implements ConfigurableApplicationContext {
/**
* 容器构建入口,该方法会刷新并重新构建整个容器。
* 如果用户调用该方法,容器中所有实例将会重新构建。
* 该方法是个模板方法,不管是什么样的ApplicationContext(web+xml、注解、内嵌web、响应式web等),
* 都会调用该方法,进入容器刷新流程。
*
* 该方法规定了Spring容器刷新的主流程:
* 从环境准备到准备容器工厂,再到后置处理器的注册、调用,容器事件的注册、监听,最后完成容器刷新等12个步骤。
*/
@Override
public void refresh() throws BeansException, IllegalStateException {
// 同步锁,锁对象用于创建和销毁方法
synchronized (this.startupShutdownMonitor) {
// 1、刷新容器前准备,记录开始时间,激活状态。初始化占位符属性源,还有验证环境变量
prepareRefresh();
// 2、创建容器beanFactory,并加载beanDefinition
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
/* ---至此,已经完成了简单容器的所有功能,下面开始对简单容器进行增强--- */
// 3、对 BeanFactory 进行功能增强,如设置BeanFactory的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
prepareBeanFactory(beanFactory);
try {
// 4、此时已加载了 BeanDefinition ,但是还没有开始实例化 Bean
// 允许在某些ApplicationContext实现中注册特殊的BeanPostProcessors等。
// 比如AbstractRefreshableWebApplicationContext的方法实现中,注册了ServletContextAwareProcessor
postProcessBeanFactory(beanFactory);
// 5、调用已注册的 BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 6、注册 BeanPostProcessor,仅仅是注册,调用在getBean的时候
registerBeanPostProcessors(beanFactory);
// 7、初始化国际化资源
initMessageSource();
// 8、初始化事件广播器
initApplicationEventMulticaster();
// 9、留给子类实现的模板方法(便于子类扩展),在单例实例化之前。
onRefresh();
// 10、注册事件监听器
registerListeners();
// 11、实例化所有非延迟加载的单例
finishBeanFactoryInitialization(beanFactory);
// 12、完成刷新过程,发布应用事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已经创建的单例以避免悬空资源。
destroyBeans();
// 重置容器的运行状态
cancelRefresh(ex);
throw ex;
}
finally {
// 清除其他公共缓存
resetCommonCaches();
}
}
}
}
4、创建容器并加载BeanDefinition
4-1、obtainFreshBeanFactory()
销毁旧Factory(如果有) 并构建新 BeanFactory
(实现类:DefaultListableBeanFactory
)。在刷新过程中,会通过loadBeanDefinitions()
来完成Bean扫描、加载过程
public abstract class AbstractApplicationContext
extends DefaultResourceLoader
implements ConfigurableApplicationContext {
/**
* 刷新并获取容器
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//刷新容器,详细见下一段代码
refreshBeanFactory();
//获取AbstractRefreshableApplicationContext中的成员变量beanFactory
//beanFactory的类型为DefaultListableBeanFactory
return getBeanFactory();
}
}
refreshBeanFactory();
该方法在此处由AbstractRefreshableApplicationContext
实现
public abstract class AbstractRefreshableApplicationContext
extends AbstractApplicationContext {
@Override
protected final void refreshBeanFactory() throws BeansException {
// 1、判断是否存在 beanFactory,如果存在则销毁所有 beanFactory 的单例bean,并且关闭 beanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//2、创建容器,实际上就是new DefaultListableBeanFactory()
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
//3、自定义设置是否允许 beanDefinition 被重写、是否允许循环引用
customizeBeanFactory(beanFactory);
//4、将bean定义加载到给定的bean工厂中,通常是通过委托给一个或多个BeanDefinitionReader
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
}
loadBeanDefinitions
在 loadBeanDefinitions
中,主要是解析 XML 文档,并注册 BeanDefinition
解析 <Bean>
标签主要是以下方法 processBeanDefinition
processBeanDefinition
当解析到 <Bean>
标签时,会执行processBeanDefinition
方法,处理给定的bean元素,解析bean定义
public class DefaultBeanDefinitionDocumentReader
implements BeanDefinitionDocumentReader {
/**
*处理给定的bean元素,解析bean定义并将其注册到注册中心。
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 1、解析Bean的属性,BeanDefinitionParserDelegate的成员变量即为Bean标签的可取值
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
//注册最后的装饰实例。
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
// 注册完成后,发送注册事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
}
不论是解析默认元素还是自定义元素,最后都会走到 DefaultListableBeanFactory
的 registerBeanDefinition
中,对XML配置文件进行解析,并注册BeanDefinition
详细源码参见文章,Spring源码-BeanDefinition
文章的 六-2-(1)
中registerBeanDefinition
的解析。
5、实例化bean(重点)
public abstract class AbstractApplicationContext
extends DefaultResourceLoader
implements ConfigurableApplicationContext {
protected void finishBeanFactoryInitialization(
ConfigurableListableBeanFactory beanFactory
) {
// ...
// (重点)实例化所有剩余的(非lazy-init)单例。
beanFactory.preInstantiateSingletons();
}
}
在 finishBeanFactoryInitialization
方法中会调用实际初始化 bean 的方法 preInstantiateSingletons()
,默认是在 DefaultListableBeanFactory
中实现
public class DefaultListableBeanFactory
extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory,
BeanDefinitionRegistry, Serializable {
/**
* 实例化所有非延迟加载的单例 bean
* @throws BeansException
*/
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 触发所有非惰性单例bean的初始化…
for (String beanName : beanNames) {
// 获取合并后的bean定义,将传入的beanDefinition及其属性中的父定义合并
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// bd.isAbstract()返回该bean是否是“抽象的”,即不打算自己实例化,而只是作为具体子bean定义的父bean。
// 判断 beanDefinition 描述的bean是否单例、是否延迟加载
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// FactoryBean 的实例化过程
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
// (重点)普通bean的实例化
else {
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
// 为所有bean触发初始化后回调
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
}
getBean()
public abstract class AbstractBeanFactory
extends FactoryBeanRegistrySupport
implements ConfigurableBeanFactory {
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
}
doGetBean
四、ApplicationContext 准备启动
在真实环境中,一般通过集成 SSM 或者 SpringBoot 来自动创建 ApplicationContext。
1、先从 SSM 开始
1、在 web.xml 配置监听器
<!-- spring监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
2、容器启动时会调用 ContextLoaderListener 中的 contextInitialized 方法。
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
...
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
...
}
3、调用父类的 initWebApplicationContext 方法,在该方法中创建、启动上下文。
public class ContextLoader {
...
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
...
try {
if (this.context == null) {
// 通过 createWebApplicationContext 方法创建上下文,默认创建 XmlWebApplicationContext
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
...
// 在该方法中调用上下文的 refresh 方法,refresh 就是启动上下文的入口
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
...
}
...
}
...
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
...
wac.refresh();
}
...
}
2、SpringBoot 启动
1、从启动类开始
@SpringBootApplication
public class DiveInSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(DiveInSpringBootApplication.class, args);
}
}
2、找到 SpringApplication 中,最后重载的 run 方法
public ConfigurableApplicationContext run(String... args) {
...
ConfigurableApplicationContext context = null;
...
try {
...
// 通过 createApplicationContext 方法创建上下文,根据 Web 环境不同创建的上下文也不同
context = createApplicationContext();
...
// 该方法用于启动上下文
refreshContext(context);
...
}
catch (Throwable ex) {
...
}
context = createApplicationContext();
...
}
3、进入 refreshContext 方法,里面调用了 refresh 方法
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
4、这里,最终也是调用 ApplicationContext 的 refresh 方法来启动上下文
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
注:这里主要讨论容器的创建和启动部分,所以省略了其他部分的代码。
可以看到虽然 SSM 和 SpringBoot 的上下文对象不同,但最终都是调用上下文中的 refresh 方法来启动。该方法是 ApplicationContext 的核心,如 Bean 注册、注入、解析 XML 、解析注解等是从该方法开始,其内部实现大致如下:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 初始化 refresh 的上下文环境,就是记录下容器的启动时间、标记已启动状态、处理配置文件中的占位符
prepareRefresh();
// 2. 初始化 BeanFactory,加载并解析配置
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
/* ---至此,已经完成了简单容器的所有功能,下面开始对简单容器进行增强--- */
// 3. 对 BeanFactory 进行功能增强,如设置BeanFactory的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
prepareBeanFactory(beanFactory);
try {
// 4. 后置处理 beanFactory,交由子类实现
postProcessBeanFactory(beanFactory);
// 5. 调用已注册的 BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注册 BeanPostProcessor,仅仅是注册,调用在getBean的时候
registerBeanPostProcessors(beanFactory);
// 7. 初始化国际化资源
initMessageSource();
// 8. 初始化事件广播器
initApplicationEventMulticaster();
// 9. 留给子类实现的模板方法
onRefresh();
// 10. 注册事件监听器
registerListeners();
// 11. 实例化所有非延迟加载的单例
finishBeanFactoryInitialization(beanFactory);
// 12. 完成刷新过程,发布应用事件
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + ex);
}
// 13.销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
this.destroyBeans();
// Reset 'active' flag.
this.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...
this.resetCommonCaches();
}
}
}
接下来的文章,将对 refresh 方法中的各部分进行详细讨论。
3、refresh()
refresh()
方法定义在 ConfigurableApplicationContext
接口中,被 AbstractApplicationContext
抽象类实现,该方法由十几个子方法组成,这些子方法各司其职,但部分子方法被 AbstractApplicationContext
的子类进行扩展,来增强功能。其中,前四个子方法主要进行上下文准备工作。
(1)prepareRefresh()
我们先从 refresh 中的 prepareRefresh()
方法开始讨论:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 初始化上下文环境,就是记录下容器的启动时间、活动状态等
prepareRefresh();
...
}
}
该方法被继承 AbstractApplicationContext 抽象类的子类进行扩展,扩展(重写)该方法的子类有:
AnnotationConfigReactiveWebServerApplicationContext
AnnotationConfigServletWebApplicationContext
AnnotationConfigServletWebServerApplicationContext
因本次演示的环境是 SpringBoot ,SpringBoot
会根据当前 Web 应用类型创建不同的上下文对象 ,如 Servlet Web、Reactive Web 等。这里演示的是 Servlet Web 应用,所以创建的上下文对象是 AnnotationConfigServletWebServerApplicationContext
。该类的 prepareRefresh
方法会被执行:
public class AnnotationConfigServletWebServerApplicationContext
extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {
...
@Override
protected void prepareRefresh() {
// 清除 Class 的元数据缓存。底层用 Map 保存元数据,执行 Map 的 clear 方法
this.scanner.clearCache();
// 调用父类,也就是 AbstractApplicationContext 的 prepareRefresh 方法
super.prepareRefresh();
}
...
}
prepareRefresh()
:
public abstract class AbstractApplicationContext {
...
private long startupDate;
private final AtomicBoolean active = new AtomicBoolean();
private final AtomicBoolean closed = new AtomicBoolean();
private Set<ApplicationEvent> earlyApplicationEvents;
...
protected void prepareRefresh() {
// 记录此上下文开始时的系统时间(以毫秒为单位)
this.startupDate = System.currentTimeMillis();
// 记录此上下文是否已关闭,这里设置为未关闭
this.closed.set(false);
// 记录此上下文是否处于活动状态,这里设置为活动状态
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// 这也是交由子类扩展的方法。具体子类为 GenericWebApplicationContext,主要是初始化属性源,
// 将 ServletContext 和 ServletConfig 属性配置添加到 Environment 环境上下文中
initPropertySources();
// 校验 Environment 中那些必备的属性配置是否存在,不存在则抛异常。
getEnvironment().validateRequiredProperties();
// 创建 ApplicationEvent 事件集合
this.earlyApplicationEvents = new LinkedHashSet<>();
}
}
refresh 中的 prepareRefresh()
方法执行结束,主要是记录容器的启动时间、活动状态、检查必备属性是否存在。
(2)obtainFreshBeanFactory()
接着进入 refresh
中的 obtainFreshBeanFactory
方法
public abstract class AbstractApplicationContext {
...
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
...
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
...
}
}
...
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 该方法也是由子类扩展,其子类有 AbstractRefreshableApplicationContext 和 GenericApplicationContext,
// 因当前是 Servlet Web 应用,所以执行的是 GenericApplicationContext 中的 refreshBeanFactory 方法。
// 该方法主要设置 BeanFactory 的 serializationId 属性值,也就是序列化id
refreshBeanFactory();
// 通过 getBeanFactory 返回 BeanFactory 对象。同样也是由子类扩展,调用的是 GenericApplicationContext 类中的 getBeanFactory 方法。
// 返回的是 DefaultListableBeanFactory 。
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
...
}
obtainFreshBeanFactory
方法很简单,但如果当前是非 Servlet Web 应用,执行的就是 AbstractRefreshableApplicationContext
中的 refreshBeanFactory
方法,那可就复杂多了,这里就不展开讨论。之后,该方法还返回了 BeanFactory
对象,从这也可以看出 ApplicationContext
底层是以 BeanFactory
为基础,逐步扩展 Spring 容器功能。
(3)prepareBeanFactory()
接着进入 refresh
中的 prepareBeanFactory
方法。prepareBeanFactory
方法主要是对 BeanFactory
做一些配置,包含各种类加载器、需要忽略的依赖以及后置处理器、解析器等,
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
...
prepareBeanFactory(beanFactory);
...
}
...
}
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 设置类加载器
beanFactory.setBeanClassLoader(getClassLoader());
// 设置表达式解析器,主要用来解析 EL 表达式; Bean 初始化完成后填充属性时会用到
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 设置属性注册解析器,主要用来解析 Bean 中的各种属性类型,如 String、int 等
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 添加一个后置处理器:ApplicationContextAwareProcessor。
// 该后置处理器用于向实现了 Aware 系列接口的 bean 设置相应属性。
// (后置处理器和 Aware 接口也是比较核心的概念,后面会有文章详细讨论)
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 以下接口,在自动注入时会被忽略,其都是 Aware 系列接口
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// 当以下特殊的 Bean 需自动注入时,指定其注入的类型 。
// 如:注入 BeanFactory 时,注入的类型对象为 ConfigurableListableBeanFactory 。
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 添加 ApplicationListenerDetector 后置处理器。
// 该后置处理器用来检测那些实现了 ApplicationListener 接口的 bean,并将其添加到应用上下文的事件广播器上。
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// 判断容器中是否存在 loadTimeWeaver Bean,如果存在则上下文使用临时的 ClassLoader 进行类型匹配。
// 集成 AspectJ 时会用到 loadTimeWeaver 对象。
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 注册和环境相关的 Bean,如 environment、systemProperties、systemEnvironment
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());
}
}
在 prepareBeanFactory 方法中,主要对 BeanFactory 添加了一系列属性项,如添加忽略自动注入的接口、添加 BeanPostProcessor 后置处理器、手动注册部分特殊的 Bean及环境相关的 Bean 。
(4)postProcessBeanFactory()
postProcessBeanFactory
方法是上下文准备的最后一步,主要用来注册 Web 请求相关的处理器、Bean及配置。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
...
postProcessBeanFactory(beanFactory);
...
}
}
该方法也是由子类进行扩展,实现该方法的子类有很多
前面也说过,当前是 Servlet Web 应用,所以创建的 ApplicationContext
上下文是 AnnotationConfigServletWebServerApplicationContext
,执行该类的 postProcessBeanFactory 方法。
public class AnnotationConfigServletWebServerApplicationContext
extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {
private final AnnotatedBeanDefinitionReader reader;
private final ClassPathBeanDefinitionScanner scanner;
private final Set<Class<?>> annotatedClasses = new LinkedHashSet<>();
private String[] basePackages;
...
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 先执行父类 ServletWebServerApplicationContext 的 postProcessBeanFactory 方法。
// 跳转到 1 查看父类实现
super.postProcessBeanFactory(beanFactory);
// basePackages 存储的是类路径。先判断是否为 null,不为 null 则通过 ClassPathBeanDefinitionScanner 的 scan 方法
// 扫描该路径下符合条件的 Class,并将 Class 信息包装成 BeanDefinition 注册到容器中,
// 当然,这里没有指定扫描路径,所以不会进入这个 if。
// (BeanDefinition 概念会在后面章节详细讨论)
if (this.basePackages != null && this.basePackages.length > 0) {
this.scanner.scan(this.basePackages);
}
// annotatedClasses 存储的 Class 集合。先判断该集合是否为空,不为空则通过
// AnnotatedBeanDefinitionReader 的 register 方法将 Class 信息包装成 BeanDefinition 注册到容器中,
// 这里同样没有设置 Class 集合内容,所以不会进入这个 if。
if (!this.annotatedClasses.isEmpty()) {
this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
}
}
}
1、
public class ServletWebServerApplicationContext extends GenericWebApplicationContext
implements ConfigurableWebServerApplicationContext {
...
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 添加 BeanPostProcessor 后置处理器:WebApplicationContextServletContextAwareProcessor,
// 该后置处理器主要是从 ConfigurableWebApplicationContext 上下文中获取 ServletContext 和 ServletConfig 对象
beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
// 添加一个 忽略自动注入的接口
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
}
...
postProcessBeanFactory
方法执行的操作和前面类似,也是添加了后置处理器和忽略自动注入的接口。
(5)总结
ApplicationContext
上下文准备工作基本结束,主要还是在 BeanFactory
中添加一系列后置处理器、注册特殊的 Bean 及设置忽略自动注入的接口。其中还提到了 Spring 容器的三个核心部分:Aware
系列接口、BeanPostProcessor
后置处理器、BeanDefinition
,这部分在后面的文章会逐步讨论。接下来将对 Spring 容器的核心功能展开讨论。