BeanFactory和ApplicationContext
2025-01-22 08:19:30    3.1k 字   
This post is also available in English and alternative languages.

Spring Framework版本:5.1.6.RELEASE (点击跳转官方文档)

在 Spring 中,有两个重要的接口,即 BeanFactory 和 ApplicationContext。本篇将介绍这两个接口,以及它们之间的区别和用法。


1. BeanFactory

BeanFactory 是 Spring 框架的核心接口之一,它负责管理和维护应用程序中的对象,通常被称为 Bean。BeanFactory 是一个轻量级的容器,它实现了依赖注入和松散耦合等功能。它提供了一个工厂模式,将应用程序的对象实例化和配置分离。还提供了生命周期管理,可以管理 Bean 的生命周期,包括初始化和销毁。


1.1. 功能

BeanFactory 接口提供了以下方法:

BeanFactory接口函数列表
  • getBean(String name):根据 Bean 的名称获取 Bean 实例。
  • getBean(Class<T>; requiredType):根据 Bean 的类型获取 Bean 实例。
  • containsBean(String name):检查 BeanFactory 是否包含指定名称的 Bean。
  • isSingleton(String name):检查指定名称的 Bean 是否是单例 Bean。
  • getAliases(String name):获取指定名称的 Bean 的所有别名。

1.2. BeanFactory 示例

1.2.1. 示例一

输出 BeanFactory 中存储的所有单例 bean 信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Slf4j
@SpringBootApplication
public class ApplicationSpringBootExample11 {
public static void main(String[] args) throws Exception {
// ...
// 输出 BeanFactory 中存储的所有单例 bean 信息
Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
singletonObjects.setAccessible(Boolean.TRUE);
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
map.entrySet().stream().filter(e -> e.getKey().startsWith("component"))
.forEach(e -> System.out.println(e.getKey() + "=" + e.getValue()));
}
}

1.2.2. 示例二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Configuration
static class Config {
@Bean("bean1")
public Bean1 buildBean1() { return new Bean1(); }
@Bean("bean2")
public Bean2 buildBean2() { return new Bean2(); }
}
static class Bean1 {
public Bean1() { System.out.println("bean1 构造器执行"); }
@Autowired
private Bean2 bean2;
public Bean2 getBean2() { return bean2; }
}
static class Bean2 {
public Bean2() { System.out.println("bean2 构造器执行"); }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

AbstractBeanDefinition configBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class)
.setScope("singleton").getBeanDefinition();

beanFactory.registerBeanDefinition("config", configBeanDefinition);

String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName); // config
}
}
  1. 创建 DefaultListableBeanFactory 对象,它是 BeanFactory 接口最重要的实现类。
  2. 接着将 Config 类封装成 BeanDefinition[1]
  3. 将 configBeanDefinition 注册到 BeanFactory 中,beanFactory.registerBeanDefinition 方法的第一个参数是 beanName。
  4. 输出 beanFactory 中所有的 beanDefinition 的 name,验证是否成功将 Config 类注册到 BeanFactory 中。

运行结果如下:

1
config

最终输出的 BeanDefinition[1] 信息中只有 “config”,说明 Config 类成功注册到 BeanFactory 中了。
不过 Config 类中 @Bean 注解没有生效,因为没有输出 Bean1 和 Bean2 的 BeanDefinition[1] 信息。这说明原始的 BeanFactory 并没有能力解析 Config 类上的 @Configuration 注解和其中的 @Bean 注解。


为使 Config 类上的 @Configuration 注解和其中的 @Bean 注解生效,需要给 BeanFactory 添加上一些 Spring 内置的 BeanFactoryPostProcessor[2] 和 BeanPostProcess[3],帮助我们处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

AbstractBeanDefinition configBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class)
.setScope("singleton").getBeanDefinition();

beanFactory.registerBeanDefinition("config", configBeanDefinition);

AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}

AnnotationConfigUtils.registerAnnotationConfigProcessors 方法,就是为 BeanFactory 添加 Spring 内置的 BeanFactoryPostProcessor[2] 和 BeanPostProcessor[3]

运行后输出的 BeanDefinition[1] 信息如下:

1
2
3
4
5
6
config
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

这些 Spring 内置的 BeanFactoryPostProcessor[2] 和 BeanPostProcessor[3],它们的作用如下:

  • internalConfigurationAnnotationProcessor:处理 @Configuration 注解的类,生成对应的 BeanDefinition[1] 对象;
  • internalAutowiredAnnotationProcessor:处理 @Autowired@Value 注解,进行自动装配;
  • internalCommonAnnotationProcessor:处理常用的注解,如 @PostConstruct@PreDestroy@Resource等;
  • internalEventListenerProcessor:处理 Spring 事件相关的注解,如 @EventListener 等;
  • internalEventListenerFactory:处理 Spring 事件相关的注解,生成对应的监听器。

需要注意的是,此时这些 BeanFactoryPostProcessor[2] 和 BeanPostProcessor[3] 只是被添加到 beanFactory 中,它们还未被运行。


从 BeanFactory 中取出所有 BeanFactoryPostProcessor[2] ,然后挨个运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

AbstractBeanDefinition configBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class)
.setScope("singleton").getBeanDefinition();

beanFactory.registerBeanDefinition("config", configBeanDefinition);

AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

Collection<BeanFactoryPostProcessor> beanFactoryPostProcessors = beanFactory
.getBeansOfType(BeanFactoryPostProcessor.class).values();
for (BeanFactoryPostProcessor processor : beanFactoryPostProcessors) {
System.out.println("BeanFactoryPostProcessor:" + processor);
processor.postProcessBeanFactory(beanFactory);
}
String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}

运行结果如下:

1
2
3
4
5
6
7
8
9
10
BeanFactoryPostProcessor:org.springframework.context.annotation.ConfigurationClassPostProcessor@4e91d63f
BeanFactoryPostProcessor:org.springframework.context.event.EventListenerMethodProcessor@3fb1549b
config
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
bean1
bean2

输出的 BeanDefinition[1] 信息中出现了 bean1 和 bean2,说明 Bean1 和 Bean2 这两个对象被成功注册到 BeanFactory 中了。也说明 @Configuration 注解被正确解析了。


接下来尝试调用 bean1.getBean2() 方法,获取 Bean1 中通过 @Autowired 注解自动注入的 Bean2 对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

AbstractBeanDefinition configBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class)
.setScope("singleton").getBeanDefinition();

beanFactory.registerBeanDefinition("config", configBeanDefinition);

AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

Collection<BeanFactoryPostProcessor> beanFactoryPostProcessors = beanFactory
.getBeansOfType(BeanFactoryPostProcessor.class).values();
for (BeanFactoryPostProcessor processor : beanFactoryPostProcessors) {
System.out.println("BeanFactoryPostProcessor:" + processor);
processor.postProcessBeanFactory(beanFactory);
}
String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}

Bean1 bean1 = beanFactory.getBean(Bean1.class);
System.out.println(bean1.getBean2());
}

运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
BeanFactoryPostProcessor:org.springframework.context.annotation.ConfigurationClassPostProcessor@4e91d63f
BeanFactoryPostProcessor:org.springframework.context.event.EventListenerMethodProcessor@3fb1549b
config
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
bean1
bean2
bean1 构造器执行
null

bean1.getBean2() 方法返回的是 null,说明 Bean1 中通过 @Autowired 自动注入 Bean2 没有生效。


@Autowired 注解自动注入,这个功能依赖 BeanPostProcessor[3],对 Bean 生命周期的各个阶段提供扩展。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

AbstractBeanDefinition configBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class)
.setScope("singleton").getBeanDefinition();

beanFactory.registerBeanDefinition("config", configBeanDefinition);

AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

Collection<BeanFactoryPostProcessor> beanFactoryPostProcessors = beanFactory
.getBeansOfType(BeanFactoryPostProcessor.class).values();
for (BeanFactoryPostProcessor processor : beanFactoryPostProcessors) {
System.out.println("BeanFactoryPostProcessor:" + processor);
processor.postProcessBeanFactory(beanFactory);
}

String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}

Collection<BeanPostProcessor> beanPostProcessors = beanFactory.getBeansOfType(BeanPostProcessor.class).values();
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
beanFactory.addBeanPostProcessor(beanPostProcessor);
}
Bean1 bean1 = beanFactory.getBean(Bean1.class);
System.out.println(bean1.getBean2());
}

从 BeanFactory 中取出所有 BeanPostProcessors[3] 接口的实现类,通过 addBeanPostProcessor 方法添加到 BeanFactory 的指定属性中。这样就可以解析如 @Autowired@Resource 等注解。

运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
BeanFactoryPostProcessor:org.springframework.context.annotation.ConfigurationClassPostProcessor@4e91d63f
BeanFactoryPostProcessor:org.springframework.context.event.EventListenerMethodProcessor@3fb1549b
config
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
bean1
bean2
bean1 构造器执行
bean2 构造器执行
com.yxcheng.example99.beanfactory.TestBeanFactoryMainApp01$Bean2@2d710f1a

通过 bean1.getBean2() 方法成功获取到自动注入其中的 Bean2 对象的信息。


通过以上示例不难发现,BeanFactory 不会主动添加 BeanFactoryPostProcessor[2] 和 BeanPostProcess[3],更不会主动调用它们;

BeanFactory 靠近顶层而且功能简单,很多扩展需要依靠别的组件实现。


2. ApplicationContext

ApplicationContext 是 BeanFactory 的子接口,它提供了更多的功能和扩展,包括国际化(MessageSource)、事件传播(ApplicationEventPublisher)、资源加载(ResourcePatternResolver)等。

ApplicationContext 是一个更加强大和复杂的容器,BeanFactory 是 Spring 的核心容器,而 ApplicationContext 扩展、组合了 BeanFactory 的功能。

applicationContext和BeanFactory继承关系

2.1. 功能

ApplicationContext 接口提供了以下方法:

  • getBean(String name):根据 Bean 的名称获取 Bean 实例。
  • getBean(ClassrequiredType):根据 Bean 的类型获取 Bean 实例。
  • containsBean(String name):检查 ApplicationContext 是否包含指定名称的 Bean。
  • isSingleton(String name):检查指定名称的 Bean 是否是单例 Bean。
  • getAliases(String name):获取指定名称的 Bean 的所有别名。
  • getMessage(String code, Object[] args, String defaultMessage, Locale locale):获取国际化消息。
  • publishEvent(ApplicationEvent event):发布事件。

2.2. ApplicationContext 示例

ApplicationContext 用于管理 Bean 的生命周期,其实现类提供了很多有用的功能。通过下面四个示例代码了解 ApplicationContext 的使用方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@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 doController() {
return (request, response) -> {
response.getWriter().print("hello");
return null;
};
}
}

@Configuration
static class Config {
@Bean
public Bean1 buildBean1() { return new Bean1(); }
@Bean
public Bean2 buildBean2(Bean1 bean1) {
Bean2 bean2 = new Bean2();
bean2.setBean1(bean1);
return bean2;
}
}

static class Bean1 { }

static class Bean2 {
private Bean1 bean1;
public Bean1 getBean1() { return bean1; }
public void setBean1(Bean1 bean1) { this.bean1 = bean1; }
}
1
2
3
4
5
6
7
8
9
<?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="bean1" class="com.yxcheng.example99.applicationcontext.TestApplicationContextMainApp01.Bean1"/>
<bean id="bean2" class="com.yxcheng.example99.applicationcontext.TestApplicationContextMainApp01.Bean2">
<property name="bean1" ref="bean1"/>
</bean>
</beans>

文件路径:src/main/resources/applicationContext/B01.xml


2.2.1. ClassPathXml 示例

此示例使用 ClassPathXmlApplicationContext 解析 Spring XML,将对应的 Bean 转换成 BeanDefinition[1] 保存到 BeanFactory 中,并根据 XML 文件中的配置,完成依赖注入。需要注意的是,"applicationContext/B01.xml" 文件路径是基于 resource 目录的。

1
2
3
4
5
6
7
8
9
private static void testClassPathXmlApplicationContext() {
ClassPathXmlApplicationContext classPathXmlApplicationContext =
new ClassPathXmlApplicationContext("applicationContext/B01.xml");
for (String beanDefinitionName : classPathXmlApplicationContext.getBeanDefinitionNames()) {
System.out.println("beanDefinitionName: " + beanDefinitionName);
}
Bean2 bean2 = classPathXmlApplicationContext.getBean(Bean2.class);
System.out.println(bean2.getBean1());
}

运行结果:

1
2
3
beanDefinitionName: bean1
beanDefinitionName: bean2
com.yxcheng.example99.applicationcontext.TestApplicationContextMainApp01$Bean1@72cc7e6f

2.2.2. FileSystemXml 示例

此示例使用 FileSystemXmlApplicationContext 解析 Spring XML,将对应的 Bean 转换成 BeanDefinition[1] 保存到 BeanFactory 中,并根据 XML 文件中的配置,完成依赖注入。需要注意的是,此处的入参是基于项目的相对路径,也可以填写文件的绝对路径。

1
2
3
4
5
6
7
8
9
private static void testFileSystemXmlApplicationContext() {
FileSystemXmlApplicationContext fileSystemXmlApplicationContext = new FileSystemXmlApplicationContext(
"springboot-example-99/src/main/resources/applicationContext/B01.xml");
for (String beanDefinitionName : fileSystemXmlApplicationContext.getBeanDefinitionNames()) {
System.out.println("beanDefinitionName: " + beanDefinitionName);
}
Bean2 bean2 = fileSystemXmlApplicationContext.getBean(Bean2.class);
System.out.println(bean2.getBean1());
}

运行结果:

1
2
3
beanDefinitionName: bean1
beanDefinitionName: bean2
com.yxcheng.example99.applicationcontext.TestApplicationContextMainApp01$Bean1@72cc7e6f

2.2.3. 横插一脚

上面的 ClassPathXml 示例FileSystemXml 示例 这两个示例,都是使用 ApplicationContext 实现类进行读取的,只需一行代码,创建对应的 ApplicationContext 实现类并传入指定 XML 文件的路径,接着会自动读取文件并解析保存到 BeanFactory 中。

如果不使用 ApplicationContext 的实现类,而是像 BeanFactory#示例二 中那样子,自己创建 BeanFactory 该如何实现?试试看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private static void testBeanFactoryAndApplicationContext() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
System.out.println("reader 读取之前的 beanDefinitionName");
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println("beanDefinitionName: " + beanDefinitionName);
}
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(new ClassPathResource("applicationContext/B01.xml"));
// reader.loadBeanDefinitions(new FileSystemResource("springboot-example-99/src/main/resources/applicationContext/B01.xml"));
System.out.println("\nreader 读取之后的 beanDefinitionName");
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println("beanDefinitionName: " + beanDefinitionName);
}
}

运行结果:

1
2
3
4
5
reader 读取之前的 beanDefinitionName

reader 读取之后的 beanDefinitionName
beanDefinitionName: bean1
beanDefinitionName: bean2

第一次输出 BeanFactory 中的 BeanDefinition[1] 时是空的。接着手动创建了一个 XmlBeanDefinitionReader 对象,指定XML文件,然后再次输出就有结果了。

相较于直接使用 ApplicationContext 的实现类,这种实现方式略显繁琐,而且 ApplicationContext 还有其他的实现类,为使用者提供更多便利。


2.2.4. AnnotationConfig 示例

此示例使用 AnnotationConfigApplicationContext 解析 Config 类上的 @Configuration 注解和其中的 @Bean 注解,然后将对应的 Bean 信息转换成 BeanDefinition[1] 并保存到 BeanFactory 中,并且完成依赖注入。

1
2
3
4
5
6
7
8
9
private static void testAnnotationConfigApplicationContext() {
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext(Config.class);
for (String beanDefinitionName : annotationConfigApplicationContext.getBeanDefinitionNames()) {
System.out.println("beanDefinitionName: " + beanDefinitionName);
}
Bean2 bean2 = annotationConfigApplicationContext.getBean(Bean2.class);
System.out.println(bean2.getBean1());
}

运行结果:

1
2
3
4
5
6
7
8
9
beanDefinitionName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanDefinitionName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanDefinitionName: org.springframework.context.annotation.internalCommonAnnotationProcessor
beanDefinitionName: org.springframework.context.event.internalEventListenerProcessor
beanDefinitionName: org.springframework.context.event.internalEventListenerFactory
beanDefinitionName: testApplicationContextMainApp01.Config
beanDefinitionName: buildBean1
beanDefinitionName: buildBean2
com.yxcheng.example99.applicationcontext.TestApplicationContextMainApp01$Bean1@72c8e7b

注意:在输出的 BeanDefinition[1] 信息中 Config 类也被解析成 BeanDefinition[1] 并保存了。


2.2.5. AnnotationConfigServletWebServer 示例

此示例使用 AnnotationConfigServletWebServerApplicationContext 启动 Web 容器,并解析 WebConfig 类上 @Configuration 和其中的 @Bean 注解,并完成依赖注入。

1
2
3
4
5
6
7
private static void testAnnotationConfigServletWebServerApplicationContext() {
AnnotationConfigServletWebServerApplicationContext context =
new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println("beanDefinitionName: " + beanDefinitionName);
}
}

运行结果:

1
2
3
4
5
6
7
8
9
10
beanDefinitionName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanDefinitionName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanDefinitionName: org.springframework.context.annotation.internalCommonAnnotationProcessor
beanDefinitionName: org.springframework.context.event.internalEventListenerProcessor
beanDefinitionName: org.springframework.context.event.internalEventListenerFactory
beanDefinitionName: testApplicationContextMainApp01.WebConfig
beanDefinitionName: servletWebServerFactory
beanDefinitionName: dispatcherServlet
beanDefinitionName: registrationBean
beanDefinitionName: /hello

3. BeanFactory 与 ApplicationContext 区别

BeanFactory 和 ApplicationContext 之间的主要区别在于功能和扩展。ApplicationContext 提供了更多的功能和扩展,如国际化、事件传播、资源加载等。它还提供了自动装配和模板设计模式等高级特性。

另一个重要的区别是 ApplicationContext 是在启动时就实例化所有 Bean,而 BeanFactory 只有在需要时才实例化 Bean(延迟加载)。这意味着 ApplicationContext 启动速度比 BeanFactory 慢,但它可以提供更快的响应时间和更好的性能。


4. Reference


  1. 1.Bean元信息的接口,它包含了Bean的Class类型、属性、依赖关系等信息。
  2. 2.BeanFactory后置处理器
  3. 3.Bean后置处理器