1 Bean
1.1 BeanFactory与ApplicationContext的区别
-
BeanFactory和ApplicationContext是基础接口与扩展的关系BeanFactory- Spring IoC容器的核心接口,提供了基本的 依赖注入(DI) 和 Bean 管理功能。
- 是 Spring 框架中最基础的容器接口,定义了 Bean 的创建、配置、生命周期管理等核心方法。
ApplicationContext- 是
BeanFactory的子接口,继承了其所有功能,并在此基础上扩展了更多企业级功能(如国际化支持、事件传播、资源访问等) - 是 Spring 框架中更常用、更高级的容器接口
- 是
-
常见实现类
-
BeanFactory 实现类:
DefaultListableBeanFactory:最常用的实现类,支持XML/Java配置。ListableBeanFactory:提供Bean列表查询功能。
-
ApplicationContext 实现类:
ClassPathXmlApplicationContext:从类路径加载XML配置文件。AnnotationConfigApplicationContext:基于注解的配置(如@Component)。WebApplicationContext:专为Web应用设计,集成Spring MVC等模块。
-
1.2 BeanFactory的作用
Ctrl+F12查看 BeanFactory 下的方法定义:
-
DefaultListableBeanFactory:最常用的实现类,支持XML/Java配置。
尝试着用反射获取一下这个Field的内容:
@SpringBootApplication
public class A01Application {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
ConfigurableApplicationContext context = SpringApplication.run(A01Application.class, args);
Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
singletonObjects.setAccessible(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()));
}
}
我们提前使用 @Component("component1") 等注解注入了两个Bean:Component1 和 Component2,然后过滤一下map打印一下我们注入的这两个Bean:
component1 : spring.Component1@6b357eb6
component2 : spring.Component2@64bebd55
1.3 ApplicationContext的扩展功能
MessageSource说明扩展了处理国际化资源的能力;ResourcePatternResolver扩展了通配符匹配资源的能力;ApplicationEventPublisher扩展了发布事件的能力;EnvironmentCapable扩展了读取系统环境变量、读取.properties、.yaml文件等配置项的能力
1.3.1 MessageSource
一般这种资源放在resource下,以 message 打头,如 messages_zh.properties
hi=你好
代码中测试:
// 处理国际化资源 MessageSource
// context.getMessage
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));
这些 Locale.CHINA 等信息,在实际开发中是通过浏览器的请求头带过来的
1.3.2 ResourcePatternResolver
主要是在 context.getResource()、context.getResources() 等方法中使用该能力,如:
Resource[] resources = context.getResources("classpath:application*");
Arrays.stream(resources).forEach(resource -> {
System.out.println(resource);
});
打印:
file [D:\workingDirectory\java_workspace\Learning\untitled\target\classes\application.yaml]
另外,如果我们现在要找 spring.factories 这样的文件,需要去jar包中找,所以在写pattern时classpath后面需要带上*:
Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
Arrays.stream(resources).forEach(resource -> {
System.out.println(resource);
});
打印:
URL [jar:file:/C:/Users/LinYangqiang/.m2/repository/cn/hutool/hutool-all/5.8.11/hutool-all-5.8.11.jar!/META-INF/spring.factories]
URL [jar:file:/C:/Users/LinYangqiang/.m2/repository/org/springframework/boot/spring-boot/2.7.12/spring-boot-2.7.12.jar!/META-INF/spring.factories]
URL [jar:file:/C:/Users/LinYangqiang/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.7.12/spring-boot-autoconfigure-2.7.12.jar!/META-INF/spring.factories]
URL [jar:file:/C:/Users/LinYangqiang/.m2/repository/org/springframework/data/spring-data-redis/2.7.12/spring-data-redis-2.7.12.jar!/META-INF/spring.factories]
URL [jar:file:/C:/Users/LinYangqiang/.m2/repository/org/springframework/data/spring-data-keyvalue/2.7.12/spring-data-keyvalue-2.7.12.jar!/META-INF/spring.factories]
URL [jar:file:/C:/Users/LinYangqiang/.m2/repository/org/springframework/data/spring-data-commons/2.7.12/spring-data-commons-2.7.12.jar!/META-INF/spring.factories]
URL [jar:file:/C:/Users/LinYangqiang/.m2/repository/org/springframework/boot/spring-boot-test/2.7.12/spring-boot-test-2.7.12.jar!/META-INF/spring.factories]
URL [jar:file:/C:/Users/LinYangqiang/.m2/repository/org/springframework/boot/spring-boot-test-autoconfigure/2.7.12/spring-boot-test-autoconfigure-2.7.12.jar!/META-INF/spring.factories]
URL [jar:file:/C:/Users/LinYangqiang/.m2/repository/org/springframework/spring-test/5.3.27/spring-test-5.3.27.jar!/META-INF/spring.factories]
URL [jar:file:/C:/Users/LinYangqiang/.m2/repository/org/springframework/spring-beans/5.3.27/spring-beans-5.3.27.jar!/META-INF/spring.factories]
1.3.3 EnvironmentCapable
// key不区分大小写
System.out.println(context.getEnvironment().getProperty("java_home"));
// 从配置文件中获取配置信息
System.out.println(context.getEnvironment().getProperty("spring.redis.port"));
打印:
D:\Software\JAVA19
6379
1.3.4 ApplicationEventPublisher
主要是使用 context.publishEvent() 方法使用事件发布的能力
提前准备好一个自定义的事件如下:
public class UserRegisteredEvent extends ApplicationEvent {
public UserRegisteredEvent(Object source) { // source代表事件源(谁发的这个事件)
super(source);
}
}
在函数中发布事件:
context.publishEvent(new UserRegisteredEvent(context));
在任何地方都可以定义事件监听器来监听发布的事件,并做出相应的动作,我们这里选择 Component2 作为事件监听:
@Slf4j
@Component
public class Component2 {
@EventListener
public void aaa(UserRegisteredEvent event) {
log.debug("{}", event);
}
}
打印:
2025-06-07 17:16:41.828 DEBUG 41436 --- [ main] spring.Component2 : spring.UserRegisteredEvent[source=org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@7216fb24, started on Sat Jun 07 17:16:39 CST 2025]
2 容器实现
2.1 BeanFactory实现的特点
2.1.1 定义Bean与手动注册
DefaultListableBeanFactory 是 BeanFactory 的一个比较典型的实现类。我们先观察一下一个 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();
beanFactory.registerBeanDefinition("config", beanDefinition);
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
}
@Configuration
static class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
static class Bean1 {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
public Bean1() {
log.info("构造 Bean1()");
}
@Autowired
private Bean2 bean2;
}
static class Bean2 {
private static final Logger log = LoggerFactory.getLogger(Bean2.class);
public Bean2() {
log.debug("构造 Bean2()");
}
}
}
代码解释:
-
创建了一个
DefaultListableBeanFactory实例作为容器; -
使用
BeanDefinitionBuilder构建了一个指向Config.class的 Bean 定义,并设置为单例作用域; -
将该 Bean 定义注册到容器中,名称为
config -
最后输出容器中所有已注册的 Bean 名称
这一步是为了观察一下,我们在下面的
Config类、Bean1等类上添加的@Configuration注解和@Bean注解是否生效。
运行代码,打印结果:
config
Process finished with exit code 0
这说明,@Configuration 和 @Bean 这样的注解实际上是没有生效的,因为手动创建 DefaultListableBeanFactory 并注册的流程并不会触发 Spring 对 @Configuration 类的完整处理流程。
解决方案:给 beanFactory 添加一下后处理器:
// 给 BeanFactory 添加一些常用的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
// 手动调用所有已注册的后处理器,才能把我们自定义的bean解析出来。
// 没有这一步的话,及时注册了 ConfigurationClassPostProcessor,也不会自动执行配置类的解析
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
registerAnnotationConfigProcessors 方法的作用是向 BeanFactory 注册了处理 Spring注解(如@Configuration、@Bean、@Autowired、@ComponentScan等)的基础设施 BeanPostProcessor 和 BeanFactoryPostProcessor。比如 ConfigurationClassPostProcessor 会解析 @Configuration 类和其中的 @Bean 方法。
添加了这行代码后,打印:
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
2.1.2 观察不同后处理器的作用
现在已经手动将我们的类通过 @Bean 注册到 BeanFactory 当中,现在尝试一下能否拿出来用。
static class Bean1 {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
public Bean1() {
log.info("构造 Bean1()");
}
@Autowired
private Bean2 bean2;
public Bean2 getBean2() {
return bean2;
}
}
观察到此处在 Bean1 中使用 @Autowired 注入了 Bean2,我们尝试获取一下能否拿到。补充代码:
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
打印结果:
18:37:18.869 [main] INFO spring.TestBeanFactory$Bean1 - 构造 Bean1()
null
说明这个 @Autowired 功能其实也没有生效。
@Autowired 为什么没生效呢?因为它是通过另外一种后处理器来实现的:

修改一下核心代码,添加手动执行注册 Bean 后处理器的步骤:
// 给 BeanFactory 添加一些常用的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
// BeanFactory 后处理器,补充Bean定义
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
// 手动执行注册的 Bean 后处理器,针对 bean 的生命周期的各个阶段提供扩展,例如 @Autowired @Resource...
beanFactory.getBeansOfType((BeanPostProcessor.class)).values().forEach(beanFactory::addBeanPostProcessor);
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
打印:
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
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
18:50:39.763 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
18:50:39.764 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'config'
18:50:39.791 [main] INFO spring.TestBeanFactory$Bean1 - 构造 Bean1()
18:50:39.799 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
18:50:39.800 [main] DEBUG spring.TestBeanFactory$Bean2 - 构造 Bean2()
spring.TestBeanFactory$Bean2@3eb738bb
Process finished with exit code 0
从日志也可以看出,只有在调用的时候才会去构造Bean。如果我们想在项目加载后就提前把所有的Bean创建好,添加:
beanFactory.preInstantiateSingletons(); // 准备好所有单例
打印:
bean1
bean2
18:53:27.575 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'config'
18:53:27.583 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
18:53:27.597 [main] INFO spring.TestBeanFactory$Bean1 - 构造 Bean1()
18:53:27.605 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
18:53:27.606 [main] DEBUG spring.TestBeanFactory$Bean2 - 构造 Bean2()
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
spring.TestBeanFactory$Bean2@bcec361
[!note]
总结:
beonFactory不会做的事
- 不会主动调用
BeanFactory后处理器- 不会主动添加 Bean 后处理器
- 不会主动初始化单例
beanFactory还不会解析${}与#{}- bean 后处理器会有排序的逻辑
2.1.3 @Autowired和@Resource谁先生效

这是 AnnotationUtils 中的实现。
先看下面的代码:
@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 {
}
新增一个接口 Inter,并新增 Bean3 和 Bean4 同时实现这个接口,并把Bean3 和 Bean4 手动注册到 Config。
接下来,我们在 Bean1 中观察以下现象:
-
使用
@Autowired时,如果对象名取为 inter 会报错:
无法识别要注入的是 bean3 还是 bean4
-
直接将对象名改为 bean3 就不会报错了,因为会根据对象名去找到底是注入哪一个:

-
使用
@Resource注解,但是传入name参数,优先取name参数
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> spring.TestBeanFactory$Bean4@6ad82709 -
同时使用
@Autowired和@Resource,哪个优先?
打印:
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> spring.TestBeanFactory$Bean3@7817fd62@Autowired是根据对象名直接找到 bean3 注入的,@Resource虽然指定了 bean4,但是由于在AnnotationUtils中的顺序在@Autowired之后,因此无效。我们在原来手动执行Bean后处理器那块打印一下,看顺序如何:
beanFactory.getBeansOfType((BeanPostProcessor.class)).values().forEach(beanPostProcessor -> { System.out.println(">>>>>" + beanPostProcessor); beanFactory.addBeanPostProcessor(beanPostProcessor); });打印:
>>>>>org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@7c7b252e >>>>>org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@4d5d943d 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 bean3 bean4可以看出是
AutowiredAnnotationBeanPostProcessor先。我们可以手动改变一下顺序:
// 手动执行注册的 Bean 后处理器,针对 bean 的生命周期的各个阶段提供扩展,例如 @Autowired @Resource... beanFactory.getBeansOfType((BeanPostProcessor.class)) .values() .stream() .sorted(beanFactory.getDependencyComparator()) .forEach(beanPostProcessor -> { System.out.println(">>>>>" + beanPostProcessor); beanFactory.addBeanPostProcessor(beanPostProcessor); });打印:
>>>>>org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@48f2bd5b >>>>>org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@7b2bbc3 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 bean3 bean4 ... >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> spring.TestBeanFactory$Bean4@8297b3a可以看出这回
@Resource对应的后处理器优先了,且最后注入的是 bean4
2.2 ApplicationContext的常见实现和用法
ApplicationContext 实现类:
ClassPathXmlApplicationContext:从类路径加载XML配置文件。AnnotationConfigApplicationContext:基于注解的配置(如@Component)。WebApplicationContext:专为Web应用设计,集成Spring MVC等模块。
2.2.1 ClassPathXmlApplicationContext
ClassPathXmlApplicationContext 是 Spring 框架中很重要的一个类,它的主要作用是加载类路径下的 XML 配置文件来初始化 Spring 容器
-
我们现在测试类中定义好两个准备注入的Bean(但是不使用注解)
static class Bean1 {} static class Bean2 { private Bean1 bean1; public void setBean1(Bean1 bean1) { this.bean1 = bean1; } public Bean1 getBean1() { return bean1; } } -
我们在类路径下创建一个配置文件
b01.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="bean1" class="spring.TestApplicationContext.Bean1"/> <bean id="bean2" class="spring.TestApplicationContext.Bean2"> <property name="bean1" ref="bean1"/> </bean> </beans> -
检查一下通过配置文件注入bean的方式是否成功注入:
public class TestApplicationContext { public static void main(String[] args) { testClassPathXmlApplicationContext(); } // 基于 classpath 下 xml 格式的配置文件夹创建 private static void testClassPathXmlApplicationContext() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("b01.xml"); for (String name : context.getBeanDefinitionNames()) { System.out.println(name); } System.out.println(context.getBean(Bean2.class).getBean1()); } }打印:
bean1 bean2 spring.TestApplicationContext$Bean1@6c40365c说明,成功注入了 bean1 和 bean2,且bean2中引用了bean1也可以成功获取。
底层做了什么?
本质上,ClassPathXmlApplicationContext 帮我们做了如下操作:
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
System.out.println("读取之前....");
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println("读取之后...");
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(new ClassPathResource("b01.xml"));
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
}
打印:
读取之前....
读取之后...
19:46:23.662 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [b01.xml]
bean1
bean2
也就是帮我们完成了:
- 创建 beanFactory
- 读取 xml 文件的 bean 标签,转换为配置
2.2.2 FileSystemXmlApplicationContext
和 ClassPathXmlApplicationContext 类似,只不过传入的是 .xml 配置文件在文件系统中的路径:
private static void testFileSystemXmlApplicationContext() {
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext(
"D:\\workingDirectory\\java_workspace\\Learning\\untitled\\src\\test\\resources\\b01.xml"
);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
传入绝对路径和相对路径都可以。
2.2.3 AnnotationConfigApplicationContext
AnnotationConfigApplicationContext 是基于注解配置 @Configuration 的 Spring 容器实现。与传统的 XML 配置方式相比,它允许开发者使用 Java 类和注解来配置 Spring 应用程序。
简单的示例代码:
public class TestApplicationContext {
public static void main(String[] args) {
testAnnotationConfigApplicationContext();
}
// 基于Java配置类来创建
private static void testAnnotationConfigApplicationContext() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
}
@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;
}
}
}
打印:
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
testApplicationContext.Config
bean1
bean2
发现除了 bean1 和 bean2 外,其他相关的 bean也被注入了,比如说 Config 类,它本身也是一个Bean。以及刚才的后处理器也是 bean,因此同样被打印出来了。
2.2.4 AnnotationConfigServletWebServerApplicationContext
AnnotationConfigServletWebServerApplicationContext 是 Spring Boot 框架中的一个核心类,它是专为基于 Servlet 的 Web 应用程序设计的 Spring 容器实现。这个类结合了注解配置能力、Web 应用上下文功能和内嵌 Web 服务器的启动能力,是 Spring Boot Web 应用的核心引擎。