此文章的实例代码存放在
gitee.com/chickwang/s... 主要是 spring 可以直接测试的,可以对 spring 的源码添加注释
github.com/WT-AHA/futu... 所有测试案例都有,没有 spring 源码的注释
一、BeanFactory 与 ApplicationContext
1、什么是 BeanFactory
BeanFactory 是一个工厂接口,负责生产和管理 bean 的一个工厂。ApplicationContext 的父接口,它才是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能。
这里所谓组合一般是直接调用上层类或者抽象类的实现,或者直接持有上层抽象类或者类的对象,进而调用他们的方法。
2、BeanFactory功能
表面上主要方法只有 getBean(), 但是它实际上的职责包括:实例化、定位、配置应用程序中的对象以及建立这些对象之间的依赖。BeanFactory 是一个工厂接口,Spring 给出的具体实现包括 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext 等。
3、重要实现 DefaultListableBeanFactory (需要记住的类名)
DefaultListableBeanFactory 是 BeanFactory 的一个默认实现,我们可以对它进行拓展以便实现自定义的 BeanFactory。
从上往下开始介绍各个类以及接口的作用:
- AliasRegistry(接口) :alias 指的是 bean 的别名,而 aliasRegistry 定义了对 alias 的增删改查等操作。
- SimpleAliasRegistry(类) :主要使用 map 作为 alias 的缓存,并对接口 AliasRegistry 进行实现。
- SingletonBeanRegistry(接口) :定义对单例的注册及获取。
- BeanFactory(接口) :定义获取 bean 及 bean 的各种属性。
- DefaultSingleTonBeanRegistry(接口) :实现了 SingletonBeanRegistry 的方法,同时继承了 SimpleAliasRegistry。
- HierarchicalBeanFactory(接口) :继承 BeanFactory,也就是在 BeanFactory 定义功能的基础上增加了对 parantFactory 的支持。
- BeanDefinitionRegistry(接口) :定义对BeanDefinition的增删改查功能,BeanDefinition就是描述一个bean的实例,包含了属性值(scope、bean的name、lazy加载模式等),构造参数以及其他更多的实现信息。
- FactoryBeanRegistrySupport(类) :在DefaultSingleTonBeanRegistry基础上增加了对FactoryBean的特殊功能。
- ConfigurableBeanFactory(接口) :提供配置Factory的各种方法,包括设置父工厂、bean的加载器、添加BeanPostProcessor等功能。
- ListableBeanFactory(接口) :根据各种条件获取bean的配置清单,可以根据bean的name、type等条件获得bean配置清单。
- AbstractBeanFactory(类) :综合FactoryBeanRegistrySupport和ConfigurableBeanFactory的功能。
- AutowireCapableBeanFactory(接口) :提供创建Bean、自动注入、初始化以及应用bean的后置处理器。
- AbstractAutowireCapableBeanFactory(类) :综合AbstractBeanFactory并对接口AutowireCapableBeanFactory进行实现
- ConfigurableListableBeanFactory:BeanFactory配置清单,指定忽略类型及接口等。
- DefaultListableBeanFactory:综合上面所有功能,主要对Bean注册后的处理。
DefaultListableBeanFactory 的功能测试:
java
package com.aha.ioc.beanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
/**
* 使用 DefaultListableBeanFactory 来创建一些 bean 实例
*/
public class TestDefaultListableBeanFactory {
interface Inter {
}
static class Bean1 {
public Bean1() {
System.out.println("构造bean1");
}
@Autowired
private Bean2 bean2;
public Bean2 getBean2() {
return bean2;
}
// @Autowired 先按照类型确定唯一 bean,根据类型不能确定唯一,然后按照变量的名称确定唯一
// 都确定不了的时候,就会根据变量类型找到多个就会报错
// Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.aha.ioc.beanFactory.TestDefaultListableBeanFactory$Inter' available: expected single matching bean but found 2: bean3,bean4
@Autowired
// @Autowired 可以跟 Qualifier 组合使用 用 Qualifier 来指定 bean 名称 找对应的 bean 来确定唯一
// @Qualifier("bean4")
// 当 Resource 没有指定 name 属性的属性 使用变量名匹配 bean 指定了 按照 name 属性匹配 bean
@Resource(name = "bean4")
private Inter bean3;
public Inter getInter() {
return bean3;
}
}
static class Bean2 {
public Bean2() {
System.out.println("构造bean2");
}
}
static class Bean3 implements Inter {
}
static class Bean4 implements Inter {
}
@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();
}
}
public static void main(String[] args) {
// beanFactory 最主要实现
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 创建 Bean 定义信息,根据自己编写的 class 获取 对应 class 的 beanDefinition
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(Config.class)
.setScope("singleton")
.getBeanDefinition();
// 向 bean 工厂中 注册 bean 定义信息
beanFactory.registerBeanDefinition("config", beanDefinition);
// 在这个时候打印 beanDefinitionName 的集合,发现只包含了 config 类的 beanDefinitionName 不包含 Bean1 -> Bean4
// 说明现在的 Config 类中的 @Configuration 和 @Bean 是不生效的
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println("<<<<<<<<< beanFactory.registerBeanDefinition 之后包含的 beanDefinitionName :" + beanDefinitionName);
}
// 给 BeanFactory 添加一些常用的后置处理器 主要包含
// org.springframework.context.annotation.internalConfigurationAnnotationProcessor
// org.springframework.context.annotation.internalAutowiredAnnotationProcessor
// org.springframework.context.annotation.internalCommonAnnotationProcessor
// org.springframework.context.event.internalEventListenerProcessor
// org.springframework.context.event.internalEventListenerFactory
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println("<<<<<<<<< AnnotationConfigUtils.registerAnnotationConfigProcessors 之后包含的 beanDefinitionName :" + beanDefinitionName);
}
// 执行 BeanFactoryPostProcessor, BeanFactoryPostProcessor 主要是对 BeanDefinition 进行增强
// 这里主要执行的是 对应 internalConfigurationAnnotationProcessor 的 ConfigurationClassPostProcessor,来支撑 @Configuration 注解的功能
// 还有 EventListenerMethodProcessor
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
System.out.println("<<< 执行了" + beanFactoryPostProcessor);
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
// 所以这边应该包含了 Bean1 -> Bean4 的 beanDefinition 了 因为可以解析 @Configuration 注解了
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println("<<<<<<<<< beanFactoryPostProcessor.postProcessBeanFactory 之后包含的 beanDefinitionName :" + beanDefinitionName);
}
// 代码块 1
// 发现这边返回了 null, 是因为 现在的 beanFactory 还不支持 @Autowired @Resource 这些注解
// Bean1 bean1 = beanFactory.getBean(Bean1.class);
// System.out.println("<<<<<< 执行了 beanFactoryPostProcessor.postProcessBeanFactory 之后的 bean1.getBean2(): " + bean1.getBean2());
// 执行 BeanPostProcessor, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
// @Autowired 对应 AutowiredAnnotationBeanPostProcessor
// @Resource 对应 CommonAnnotationBeanPostProcessor(它还会处理 @PostConstruct 和 @PreDestory)
assert beanFactory.getDependencyComparator() != null;
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
// 功能相似的 BeanPostProcessor 例如 AutowiredAnnotationBeanPostProcessor CommonAnnotationBeanPostProcessor
// 加载的顺序就至关重要的,会根据 beanFactory 的 DependencyComparator 来进行排序, BeanPostProcessor 都维护了 order
// 属性 AutowiredAnnotationBeanPostProcessor 为 Ordered.LOWEST_PRECEDENCE - 2
// CommonAnnotationBeanPostProcessor 为 Ordered.LOWEST_PRECEDENCE - 3 越小优先级越高
// 所以 common 先加载, autowired 后加载,所以在 @Autowired 和 @Resource 都存在的时候应该按照 @Resource 来注入
.sorted(beanFactory.getDependencyComparator())
.forEach(beanPostProcessor -> {
System.out.println("<<< 执行beanFactory.addBeanPostProcessor: " + beanPostProcessor);
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
// 准备好所有单例, beanFactory 的单例是懒加载的, spring 的 bean 默认是单例的,应该提前加载好,执行下面这个方法
beanFactory.preInstantiateSingletons();
// 这边不能与 代码块1 同时出现,代码块1 在没有添加 BeanPostProcessor 之前就获取了 bean 这边在获取也不会执行 beanPostProcessor 了
// 发现这边返回了 null, 是因为 现在的 beanFactory 还不支持 @Autowired @Resource 这些注解
Bean1 bean1 = beanFactory.getBean(Bean1.class);
System.out.println("<<<<<< 执行了 beanFactory.addBeanPostProcessor 之后的 bean1.getBean2(): " + bean1.getBean2());
// BeanPostProcessor 加载顺序问题
System.out.println("<<<<<< 执行了 beanFactory.addBeanPostProcessor 之后的 bean1.getBean2(): " + bean1.getInter());
}
}
总结:
DefaultListableBeanFactory 和它的上层实现
- 可以手动通过 BeanDefinitionBuilder.genericBeanDefinition 来获取 BeanDefinition
- 需要手动通过 registerBeanDefinition 来注册 BeanDefinition
- 测试 BeanDefinition 之后是不会解析 @Configuration 和 @Bean 这些注解的
- DefaultListableBeanFactory 中原本是没有 BeanFactoryPostProcessor 和 BeanPostProcessor 的
- 需要主动调用 AnnotationConfigUtils.registerAnnotationConfigProcessors 给他添加
- 然后执行 beanFactoryPostProcessor.postProcessBeanFactory 这样就可以支持 @Configuration 注解了,具体是哪一个 beanFactoryPostProcessor 支撑的看代码示例即可 (注意 beanFactoryPostProcessor 增强主要是增强 BeanDefinition 不会去对 Bean 的属性进行增强,所以它还不支持 @Autowired @Resource 这些注解)
- 然后 beanFactory.addBeanPostProcessor(beanPostProcessor); 来支撑 @Autowired @Resource。 待办1: 看什么时候增强这边看只是添加了 beanPostProcessor 没有执行
- DefaultListableBeanFactory 对于单例也是懒加载的,通过 beanFactory.preInstantiateSingletons(); 实现预加载
- BeanPostProcessor 有加载顺序问题,通过每个 BeanPostProcessor 实现的 Ordered 来排序,待办2: 具体的排序规则有时间可以探究一下怎么实现的
- 待办3: 目前执行调用流程是清楚了,但是具体的逻辑还没有看,比如是怎么解析 @Configuration @Autowired @Resource 这些注解的
4、什么是 ApplicationContext (接口)
由 BeanFactory 派生而来,提供了更多面向实际应用的功能,以一种更向面向框架的方式工作以及对上下文进行分层和实现继承。其既派生自 BeanFactory 也组合使用 BeanFactory 获取 bean,并相对于 BeanFactory 扩展了一些功能。
主要是增强和扩展 BeanFactory 比如说 DefaultListableBeanFactory 还要手动调用 BeanDefinitionBuilder.genericBeanDefinition 手动 registerBeanDefinition 等等。ApplicationContext 就不需要了,它(是接口,他的实现类或者抽象类)底层应该也是通过这种方式来做的(待办4:确认是不是这样做的)对于扩展参考章节 5
5、ApplicationContext 扩展了什么
我们可以看到 ApplicationContext 除了继承自 BeanFactory 接口外,还继承了额外的扩展接口分别是: MessageSource、ResourcePatternResolver、ApplicationEventPublisher、EnviromentCapable 这四个接口,这四个接口就是 ApplicationContext 相对于 BeanFactory 扩展的额外的功能。
- MessageSource:用于解析消息,并且支持消息参数化和国际化。
- ResourcePatternResolver: 用于资源访问,例如URL和文件。
- ApplicationEventPublisher: 用于时间发布。
- EnviromentCapable: 整合 Environment 环境。
具体参考代码示例:
java
package com.aha.common.spring.ioc.applicationContext;
import com.aha.common.spring.event.RegisterInfo;
import com.aha.common.spring.event.RegisterSuccessEvent;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.util.Locale;
import java.util.Map;
/**
* 测试 ApplicationContext 相对于 beanFactory 的扩展功能
* 因为监听程序写在 event 包下需要添加 scanBasePackages = {"com.aha.common"}
*/
@SpringBootApplication(scanBasePackages = {"com.aha.common"})
public class TestApplicationContextExtend {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(TestApplicationContextExtend.class, args);
// 国际化 需要 resources 中的配置文件支持 hi 为 key
System.out.println("\n国际化示例--------------------------------------");
System.out.println(context.getMessage("hi", null, Locale.CHINA));
System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
System.out.println(context.getMessage("hi", null, Locale.JAPANESE));
System.out.println("----------------------------------------------\n");
// 资源访问
System.out.println("资源访问示例-------------------------------------");
Resource[] resources = new Resource[0];
try {
// classpath 是只扫描 当前项目 resources 下,classpath* 就是包含所有 jar 包下的 resources
resources = context.getResources("classpath*:META-INF/spring.factories");
} catch (IOException e) {
e.printStackTrace();
}
for (Resource resource : resources) {
System.out.println("获取到所有的spring.factories文件为---" + resource);
}
System.out.println("----------------------------------------------\n");
// 事件发布
System.out.println("事件发布示例-------------------------------------\n");
context.publishEvent(new RegisterSuccessEvent(new RegisterInfo().setUsername("aha").setSecret("abc")));
// 环境参数
System.out.println("获取环境参数示例----------------------------------------");
ConfigurableEnvironment environment = context.getEnvironment();
Map<String, Object> systemEnvironment = environment.getSystemEnvironment();
systemEnvironment.forEach((key, value) -> System.out.println("环境参数的KEY为----" + key + "----环境参数的value为----" + value));
System.out.println("------------------------------------------------------\n");
}
}
6、ApplicationContext 的一些实现
Spring 的发展历史较为悠久,因此很多资料还在讲解它较旧的实现,这里出于怀旧的原因,把它们都列出来,供大家参考
- ClassPathXmlApplicationContext:从类路径查找 XML 配置文件,创建容器(旧)
- FileSystemXmlApplicationContext:从磁盘路径查找 XML 配置文件,创建容器(旧)
- XmlWebApplicationContext: 传统 SSM 整合时,基于 XML 配置文件的容器(旧)
- AnnotationConfigWebApplicationContext:传统 SSM 整合时,基于 java 配置类的容器(旧)
- AnnotationConfigApplicationContext: Spring boot 中非 web 环境容器(新)
- AnnotationConfigServletWebServerApplicationContext: Spring boot 中 servlet web 环境容器(新)
- AnnotationConfigReactiveWebServerApplicationContext: Spring boot 中 reactive web 环境容器(新)
另外要注意的是,后面这些带有 ApplicationContext 的类都是 ApplicationContext 接口的实现,但它们是组合了 DefaultListableBeanFactory 的功能,并非继承而来。
其中的几种实现参考代码示例:
java
package com.aha.common.spring.ioc.applicationContext;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.mvc.Controller;
public class TestKindsOfImplForApplicationContext {
static class Bean1 {
public Bean1() {
System.out.println("构造bean1");
}
private Bean2 bean2;
public void setBean2(Bean2 bean2) {
this.bean2 = bean2;
}
public Bean2 getBean2() {
return bean2;
}
}
static class Bean2 {
public Bean2() {
System.out.println("构造bean2");
}
}
@Configuration
static class Config {
@Bean
public Bean1 bean1(Bean2 bean2) {
Bean1 bean1 = new Bean1();
bean1.setBean2(bean2);
return bean1;
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
// web 环境配置类如下,实现 springBoot 的基础功能
@Configuration
static class WebConfig {
// 创建 servlet Web容器
@Bean
public ServletWebServerFactory servletWebServerFactory(){
return new TomcatServletWebServerFactory();
}
// 创建 Mvc 的 dispatcherServlet
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
// 注册 mvc 的 dispatcherServlet 指定拦截路径
@Bean
public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}
// 编写一个 controller
@Bean("/hello")
public Controller controller1() {
return (request, response) -> {
response.getWriter().print("hello");
return null;
};
}
}
public static void main(String[] args) {
// 1. ClassPathXmlApplicationContext 就是使用类路径去查找 xml 配置的路径 基于 classPath 的路径
System.out.println("========= ClassPathXmlApplicationContext 就是使用类路径去查找 xml 配置的路径 基于 classPath 的路径 ============");
ClassPathXmlApplicationContext classPathXmlApplicationContext =
new ClassPathXmlApplicationContext("spring/ioc/applicationContext/testKindsOfImplForApplicationContext.xml");
Bean1 bean1 = classPathXmlApplicationContext.getBean(Bean1.class);
for (String name : classPathXmlApplicationContext.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(bean1);
System.out.println(bean1.getBean2());
// 2. FileSystemXmlApplicationContext 就是使用文件系统路径去查找 xml 配置的路径 基于 工程的 future 的路径
System.out.println("========= FileSystemXmlApplicationContext 就是使用文件系统路径去查找 xml 配置的路径 基于 工程的 future 的路径 ============");
FileSystemXmlApplicationContext fileSystemXmlApplicationContext =
new FileSystemXmlApplicationContext("common/src/main/resources/spring/ioc/applicationContext/testKindsOfImplForApplicationContext.xml");
Bean1 bean11 = fileSystemXmlApplicationContext.getBean(Bean1.class);
for (String name : fileSystemXmlApplicationContext.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(bean11);
System.out.println(bean11.getBean2());
// 3. annotationConfigApplicationContext, 基于 java 配置类来创建
System.out.println("========= annotationConfigApplicationContext, 基于 java 配置类来创建 ============");
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext(Config.class);
for (String name : annotationConfigApplicationContext.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(annotationConfigApplicationContext.getBean(Bean1.class).getBean2());
// 4. annotationConfigServletWebServerApplicationContext, 基于 web 环境的,springBoot 内嵌 tomcat 应该使用的就是这种方式
System.out.println("========= annotationConfigApplicationContext, 基于 java 配置类来创建 ============");
AnnotationConfigServletWebServerApplicationContext annotationConfigServletWebServerApplicationContext =
new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
for (String name : annotationConfigServletWebServerApplicationContext.getBeanDefinitionNames()) {
System.out.println(name);
}
}
}