1 容器和Bean

72 阅读9分钟

1 Bean

1.1 BeanFactory与ApplicationContext的区别

image.png

  1. BeanFactoryApplicationContext 是基础接口与扩展的关系

    • BeanFactory
      • Spring IoC容器的核心接口,提供了基本的 依赖注入(DI) 和 Bean 管理功能。
      • 是 Spring 框架中最基础的容器接口,定义了 Bean 的创建、配置、生命周期管理等核心方法。
    • ApplicationContext
      • BeanFactory 的子接口,继承了其所有功能,并在此基础上扩展了更多企业级功能(如国际化支持、事件传播、资源访问等)
      • 是 Spring 框架中更常用、更高级的容器接口
  2. 常见实现类

    • BeanFactory 实现类

      • DefaultListableBeanFactory:最常用的实现类,支持XML/Java配置。
      • ListableBeanFactory:提供Bean列表查询功能。
    • ApplicationContext 实现类

      • ClassPathXmlApplicationContext:从类路径加载XML配置文件。
      • AnnotationConfigApplicationContext:基于注解的配置(如 @Component)。
      • WebApplicationContext:专为Web应用设计,集成Spring MVC等模块。

1.2 BeanFactory的作用

image.png

Ctrl+F12查看 BeanFactory 下的方法定义:

image.png

  • DefaultListableBeanFactory:最常用的实现类,支持XML/Java配置。

    image.png

image.png

尝试着用反射获取一下这个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:Component1Component2,然后过滤一下map打印一下我们注入的这两个Bean:

component1 : spring.Component1@6b357eb6
component2 : spring.Component2@64bebd55

1.3 ApplicationContext的扩展功能

image.png

  • MessageSource 说明扩展了处理国际化资源的能力;
  • ResourcePatternResolver 扩展了通配符匹配资源的能力;
  • ApplicationEventPublisher 扩展了发布事件的能力;
  • EnvironmentCapable 扩展了读取系统环境变量、读取.properties.yaml文件等配置项的能力

1.3.1 MessageSource

image.png

一般这种资源放在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));

image.png

这些 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与手动注册

DefaultListableBeanFactoryBeanFactory 的一个比较典型的实现类。我们先观察一下一个 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()");
        }
    }
}

代码解释:

  1. 创建了一个 DefaultListableBeanFactory 实例作为容器;

  2. 使用 BeanDefinitionBuilder 构建了一个指向 Config.class 的 Bean 定义,并设置为单例作用域;

  3. 将该 Bean 定义注册到容器中,名称为 config

  4. 最后输出容器中所有已注册的 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等)的基础设施 BeanPostProcessorBeanFactoryPostProcessor。比如 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 为什么没生效呢?因为它是通过另外一种后处理器来实现的:

image-20250607184605340转存失败,建议直接上传图片文件

修改一下核心代码,添加手动执行注册 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]

总结:

  1. beonFactory 不会做的事
    1. 不会主动调用 BeanFactory 后处理器
    2. 不会主动添加 Bean 后处理器
    3. 不会主动初始化单例
    4. beanFactory还不会解析${}#{}
  2. bean 后处理器会有排序的逻辑

2.1.3 @Autowired和@Resource谁先生效

image-20250607185751086转存失败,建议直接上传图片文件

这是 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,并新增 Bean3Bean4 同时实现这个接口,并把Bean3Bean4 手动注册到 Config

接下来,我们在 Bean1 中观察以下现象:

  1. 使用 @Autowired 时,如果对象名取为 inter 会报错:

    image-20250607190419781转存失败,建议直接上传图片文件

    无法识别要注入的是 bean3 还是 bean4

  2. 直接将对象名改为 bean3 就不会报错了,因为会根据对象名去找到底是注入哪一个:

    image-20250607190512792转存失败,建议直接上传图片文件

  3. 使用 @Resource 注解,但是传入 name 参数,优先取 name 参数

    image-20250607190706033转存失败,建议直接上传图片文件

    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    spring.TestBeanFactory$Bean4@6ad82709
    
  4. 同时使用 @Autowired@Resource,哪个优先?

    image-20250607190819672转存失败,建议直接上传图片文件

    打印:

    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    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 容器

  1. 我们现在测试类中定义好两个准备注入的Bean(但是不使用注解)

    static class Bean1 {}
    
    static class Bean2 {
    
        private Bean1 bean1;
    
        public void setBean1(Bean1 bean1) {
            this.bean1 = bean1;
        }
    
        public Bean1 getBean1() {
            return bean1;
        }
    }
    
  2. 我们在类路径下创建一个配置文件 b01.xml

    image-20250607193454389转存失败,建议直接上传图片文件

    <?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>
    
  3. 检查一下通过配置文件注入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 应用的核心引擎。

3 Bean的生命周期