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 接口提供了以下方法:
- 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 { 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); } }
|
- 创建 DefaultListableBeanFactory 对象,它是 BeanFactory 接口最重要的实现类。
- 接着将 Config 类封装成 BeanDefinition[1],
- 将 configBeanDefinition 注册到 BeanFactory 中,
beanFactory.registerBeanDefinition
方法的第一个参数是 beanName。 - 输出 beanFactory 中所有的 beanDefinition 的 name,验证是否成功将 Config 类注册到 BeanFactory 中。
运行结果如下:
最终输出的 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 的功能。
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")); 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