介绍
在 Spring 框架中,ApplicationContext
是核心接口之一,主要用于容纳和管理 Spring 容器中的所有 Bean 实例。它扩展了 BeanFactory
接口,并提供了更丰富的功能,包括国际化支持、事件传播、AOP支持等。它是 Spring IoC(Inversion of Control,控制反转)容器的核心接口之一,负责管理应用程序的生命周期和组件依赖关系。
目录
3. 基于 ApplicationContext 的工厂模式(不同类型的 ApplicationContext 实现)
6. isPrototype() 和 isSingleton() 方法
5. 在springBoot中使用ApplicationContext
6.3 BeanFactory与ApplicationContext的关系
1. ApplicationContext
的概念
ApplicationContext
是一个容器,它负责初始化、配置和管理应用程序中的所有对象(即 Bean)。在 Spring 中,Bean 是由容器管理的 Java 对象,容器根据配置文件(如 XML 文件、注解或 Java 配置类)来实例化和管理这些对象。ApplicationContext
提供了一种标准的方式来访问这些 Bean,并且处理这些 Bean 之间的依赖关系。
2. ApplicationContext
的作用
1. 管理 Bean 的生命周期:
ApplicationContext
会负责整个应用程序中所有 Bean 的创建、配置和销毁(如果有需要)。通过依赖注入(DI),它将 Bean 的依赖关系注入到每个 Bean 实例中。
2. 支持国际化(i18n):
ApplicationContext
提供了国际化支持,允许开发人员在应用程序中根据不同的区域和语言环境加载不同的资源文件。
3. 事件发布与监听:
ApplicationContext
支持事件的发布和监听。Spring 中的应用事件机制可以让你在容器中发布事件,并允许对象对事件做出响应。
4. Bean 查找:
ApplicationContext
提供了获取 Bean 实例的功能。可以通过 Bean 的名称或类型获取容器中已经创建好的 Bean。
5. AOP 支持:
ApplicationContext
支持面向切面编程(AOP),允许你在特定的业务逻辑上增加横切关注点,如日志记录、事务管理等。
3. ApplicationContext的调用方式
ApplicationContext
可以通过多种方式创建和初始化,通常有以下几种调用方式:
1. 基于 XML 配置的调用方式
Spring 框架最早的配置方式是基于 XML 配置文件,通过 ClassPathXmlApplicationContext
类来加载配置文件并初始化 ApplicationContext
。
假设我们有一个名为 beans.xml
的配置文件,里面定义了一些 Bean:
<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="myBean" class="com.example.MyBean"/>
</beans>
在 Java 代码中,我们可以通过 ClassPathXmlApplicationContext
来加载这个 XML 配置文件,并初始化 ApplicationContext
:
ClassPathXmlApplicationContext
会从类路径下加载beans.xml
配置文件,并根据文件中的定义创建相应的 Bean。- 通过
getBean()
方法获取容器中的 Bean 实例。
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyApp {
public static void main(String[] args) {
// 加载配置文件,初始化 Spring 容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 获取 Bean
MyBean myBean = (MyBean) context.getBean("myBean");
// 使用 Bean
myBean.someMethod();
}
}
2. 基于注解配置的调用方式(Java 配置)
随着 Spring 的发展,基于注解的配置方式逐渐成为主流。这种方式不需要使用 XML 文件,而是通过 Java 配置类来定义 Bean 和其他配置信息。
使用 AnnotationConfigApplicationContext
来加载 Java 配置类。
假设我们有一个 Java 配置类 AppConfig
,通过 @Configuration
注解声明它为配置类,并通过 @Bean
注解定义 Bean。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public MyBean myBean() {
return new MyBean();
}
}
在 Java 代码中,通过 AnnotationConfigApplicationContext
来初始化 ApplicationContext
:
AnnotationConfigApplicationContext
是用于加载基于 Java 注解配置的容器,它接受一个或多个配置类(如AppConfig.class
)作为参数。- 配置类通过
@Configuration
注解声明,并通过@Bean
注解提供 Bean 的定义。 getBean()
方法可以通过 Bean 的类型来获取容器中的 Bean。
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MyApp {
public static void main(String[] args) {
// 创建并初始化 ApplicationContext
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 获取 Bean
MyBean myBean = context.getBean(MyBean.class);
// 使用 Bean
myBean.someMethod();
}
}
3. 基于 ApplicationContext
的工厂模式(不同类型的 ApplicationContext
实现)
Spring 提供了多种类型的 ApplicationContext
实现,适用于不同的场景。除了上面介绍的 ClassPathXmlApplicationContext
和 AnnotationConfigApplicationContext
,Spring 还提供了以下实现类:
FileSystemXmlApplicationContext(基于
文件系统加载)
GenericWebApplicationContext(
与 Spring Web 配合使用)
GenericApplicationContext(
适用于非 Web 应用程序)
GenericXmlApplicationContext(
适用于不在类路径中的 XML 配置文件)
4. ApplicationContext的常用函数
1. getBean()
功能:用于从容器中获取一个 Bean 实例。可以通过 Bean 名称或类型来获取。
常用形式:
Object getBean(String name); // 通过名称获取 Bean
<T> T getBean(Class<T> requiredType); // 通过类型获取 Bean
<T> T getBean(String name, Class<T> requiredType); // 通过名称和类型获取 Bean
示例:
MyBean myBean = context.getBean("myBean", MyBean.class);
2. getBeansOfType()
方法
功能:获取容器中指定类型的所有 Bean 实例。
示例:
Map<String, MyBean> beans = context.getBeansOfType(MyBean.class);
3. getApplicationName()
方法
功能:获取当前应用程序的名称(从配置中读取)。
示例:
String appName = context.getApplicationName();
4. getParent()
方法
功能:获取当前 ApplicationContext
的父容器(如果有的话)。
示例:
ApplicationContext parentContext = context.getParent();
5. containsBean()
方法
功能:检查容器中是否存在指定名称的 Bean。
示例:
boolean exists = context.containsBean("myBean");
6. isPrototype()
和 isSingleton()
方法
功能:检查容器中的 Bean 是否为原型模式(每次请求都会创建一个新的实例)或者单例模式(容器中只有一个实例)。
示例:
boolean isSingleton = context.isSingleton("myBean"); boolean isPrototype = context.isPrototype("myBean");
5. 在springBoot中使用ApplicationContext
Spring Boot 项目通常会自动配置并初始化 ApplicationContext
,开发者不需要显式创建它。Spring Boot 内部使用了 AnnotationConfigApplicationContext
或者 GenericWebApplicationContext
来加载应用的配置。
在 Spring Boot 中,SpringApplication.run()
会启动一个内嵌的 Spring 容器并初始化 ApplicationContext
,而你通常会通过注入依赖(使用 @Autowired
)来访问容器中的 Bean,而无需手动获取 ApplicationContext
。
@SpringBootApplication
public class MySpringBootApp {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApp.class, args);
}
}
6.ApplicationContext的工作原理
理解 ApplicationContext
的工作原理,关键在于理解它如何管理 Bean 的生命周期和依赖关系。
6.1 初始化过程
当 Spring 容器启动时,ApplicationContext
会执行以下几个步骤来初始化和管理 Bean:
6.1.1. 加载配置文件或配置类,扫描并注册Bean
ApplicationContext
的初始化过程首先要加载应用程序的配置。这些配置通常是通过 XML 文件、注解配置类或两者结合来完成的。
- 如果是 XML 配置文件,使用如
ClassPathXmlApplicationContext
或GenericXmlApplicationContext
类来加载和解析 XML 配置文件。 - 如果是基于 Java 注解的配置,使用
AnnotationConfigApplicationContext
类来加载 Java 配置类(通常是用@Configuration
注解的类)。
Spring 通过类路径扫描来查找和注册 Bean。在 Java 配置类中,@ComponentScan
注解指定了扫描包的位置,Spring 会根据这个包路径来扫描类路径中的所有候选组件类。这些类通常会有 @Component
、@Service
、@Repository
、@Controller
等注解,Spring 将这些类作为 Bean 注册到容器中。
每当 Spring 扫描到一个符合条件的类时,它会将该类注册为 Bean 定义(BeanDefinition
)。每个 Bean 定义包括 Bean 的类名、作用域、依赖、初始化方法、销毁方法等配置信息。注册 Bean 定义后,Spring 容器就能根据这些定义来实例化、初始化和管理这些 Bean。
6.1.2. 实例化 所有的Bean,根据配置的作用域来确定实例化策略
当 ApplicationContext
加载并注册完所有的 Bean 定义后,接下来就会实例化这些 Bean。实例化的过程如下:
-
单例 Bean(Singleton Scope):对于单例作用域的 Bean,Spring 容器会在容器启动时实例化所有的 Bean 并缓存起来。单例 Bean 只会在容器中存在一个实例,整个应用上下文中共享这一个实例。
-
原型 Bean(Prototype Scope):对于原型作用域的 Bean,每次从容器中获取时,Spring 都会创建一个新的实例。
-
其他作用域:如请求作用域(Request)、会话作用域(Session)等,Spring 会根据作用域的不同,在不同的生命周期内实例化 Bean。
6.1.3 处理依赖注入
Spring 容器通过依赖注入(DI)机制来管理 Bean 之间的依赖关系。在 Bean 创建后,Spring 会自动注入它们所依赖的其他 Bean。通常,Spring 使用构造器注入、Setter 注入、或字段注入来处理这些依赖关系。
6.1.4 执行Bean 后处理器,允许在Bean初始化前后进行处理
如果注册了 Bean 后处理器(如 BeanPostProcessor
),它们会在 Bean 初始化之前和之后进行处理。Bean 后处理器可以用来修改 Bean 的属性,执行额外的逻辑,或者进行某些验证。
BeanPostProcessor
是 Spring 提供的一种机制,允许开发者在 Bean 初始化之前和之后对 Bean 进行处理。Spring 会在 Bean 完成依赖注入后,但在初始化前,调用所有注册的 BeanPostProcessor
的 postProcessBeforeInitialization
方法,然后调用初始化方法(如 @PostConstruct
或 InitializingBean
接口中的 afterPropertiesSet
),最后再调用 postProcessAfterInitialization
方法。
6.1.5 生命周期管理
Spring 管理 Bean 的生命周期,包括初始化、销毁等阶段。可以通过实现 InitializingBean
和 DisposableBean
接口,或者在配置文件中指定初始化方法和销毁方法来定制生命周期。
6.2 如何管理Bean
Spring 通过 ApplicationContext
和 BeanFactory
来管理 Bean。ApplicationContext
继承自 BeanFactory
,是一个更高级的容器,它除了提供基本的 IoC 功能(如 Bean 的管理),还包括了事件广播、国际化支持等功能。
6.2.1 Bean 定义和注册
每个 Bean 在 Spring 容器中都对应一个 Bean 定义(BeanDefinition
)。BeanDefinition
是一个描述 Bean 配置和属性的元数据,它包括:
- Bean 类名:Bean 实现的类。
- 构造器参数:用来创建 Bean 实例的构造器参数。
- 属性值:Bean 需要注入的属性。
- 作用域:指定 Bean 的作用域(如单例、原型等)。
- 生命周期方法:定义初始化和销毁方法。
6.2.2 Bean 实例化
Spring 容器通过 BeanDefinition
来创建 Bean 实例,通常使用反射机制来实例化 Bean 对象。如果是单例作用域的 Bean,Spring 容器会在启动时就创建这些 Bean 实例;如果是原型作用域的 Bean,则每次请求都会创建新的 Bean 实例。
6.2.3 依赖注入(DI)
依赖注入(DI)是 Spring 管理 Bean 之间依赖关系的核心机制。ApplicationContext
负责注入依赖并管理 Bean 间的关系。
Spring 支持三种常见的依赖注入方式:
- 构造器注入:通过构造方法传入依赖的 Bean。
- Setter 注入:通过 setter 方法设置依赖的 Bean。
- 字段注入:直接通过反射注入 Bean(使用
@Autowired
注解)。
6.2.4 Bean 生命周期管理
Spring 提供了强大的 Bean 生命周期管理机制,涵盖了 Bean 的初始化和销毁过程。Spring 容器会在适当的时机调用 @PostConstruct
和 @PreDestroy
注解标记的方法,或者调用实现了 InitializingBean
和 DisposableBean
接口的相关方法。
6.2.5 作用域管理
Spring 支持多种 Bean 作用域,控制 Bean 的生命周期:
- 单例(Singleton):默认作用域,Spring 容器只会创建一个 Bean 实例,并在整个应用上下文中共享该实例。
- 原型(Prototype):每次从容器获取 Bean 时,都会创建一个新的实例。
- 请求(Request):每次 HTTP 请求都会创建一个新的 Bean 实例,适用于 Web 应用。
- 会话(Session):每个 HTTP 会话创建一个新的 Bean 实例,适用于 Web 应用。
- 全局会话(Global Session):每个全局 HTTP 会话创建一个新的 Bean 实例,适用于基于 Portlet 的应用。
6.3 BeanFactory与ApplicationContext的关系
BeanFactory
是 Spring 容器的最基本接口,它只提供最基本的 Bean 创建和管理功能。而 ApplicationContext
扩展了 BeanFactory
,提供了更多的功能。ApplicationContext
允许通过以下方式来管理 Bean:
- 自动装配(Autowiring):通过
@Autowired
注解自动满足依赖关系。 - 事件机制:
ApplicationContext
可以广播事件,并提供事件监听器(ApplicationListener
)来处理这些事件。 - 国际化支持:
ApplicationContext
支持通过MessageSource
进行消息资源的管理。
7. 总结
ApplicationContext
作为 Spring 的核心容器,通过管理 Bean 的生命周期、依赖注入、事件机制、AOP、作用域等,来提供丰富的功能。它通过对 BeanDefinition
的管理来定义和注册 Bean,并通过依赖注入的方式将它们组合成一个完整的应用程序。ApplicationContext
继承自 BeanFactory
,提供了更高级的功能,使得 Spring 成为一个功能全面且灵活的框架。