一、理解下ApplicationContext的设计
(一)功能性的理解
ApplicationContext 提供了一个轻量级、灵活、可扩展的容器,能帮助我们更加轻松地构建和管理复杂的应用程序,其通过依赖注入和控制反转等技术,降低了组件之间的耦合度,提高了代码的可维护性和可测试性,同时还提供了丰富的功能和扩展点可以更加灵活地满足不同项目的需求。
从基本的官方网站 Spring | Home中来重新体会的话,基本的功能性可以初步总结以下几点:
-
Bean 实例化和管理:创建、配置和管理应用程序中的 bean 实例,可以根据配置文件或注解中的信息来实例化 bean,并且负责处理 bean 之间的依赖关系。
-
依赖注入(DI):支持依赖注入,即自动将 bean 之间的依赖关系注入到相应的属性中。可以通过构造函数、Setter 方法或字段注入的方式来实现依赖注入,降低组件之间的耦合度。
-
控制反转(IoC):实现了控制反转,即由容器负责管理组件的生命周期和依赖关系,而不是由组件自己来管理。
-
AOP 支持:提供了对面向切面编程(AOP)的支持,可以在不修改原有代码的情况下,通过切面来实现诸如日志记录、事务管理、安全性等与业务逻辑无关的功能。
-
事件传播:提供了事件传播机制,允许 bean 之间进行通信,并且可以基于事件来触发特定的逻辑。使组件之间解耦更彻底,同时也提高了应用程序的可扩展性和灵活性。
-
国际化支持:支持国际化,允许开发人员在应用程序中使用多种语言和地区的资源。提供了统一接口来访问国际化资源,并且可根据用户的语言和地区设置动态加载相应的资源。
-
资源管理:不仅管理 bean,还管理应用程序中的其他资源,如消息、国际化资源、文件等。它提供了统一的接口来访问这些资源,并提供了便利的方法来加载和管理它们。
-
生命周期管理:负责管理 bean 的生命周期,包括实例化、初始化、销毁等过程。可以通过实现特定的接口或注解来定义 bean 的生命周期回调方法,从而在 bean 的生命周期中执行特定的逻辑。
更多理解性的内容还是通过官方文档自行体会,以上只是个人视角。
(二)ApplicationContext 结构类图
Spring Framework 中的 ApplicationContext 接口是 Spring 容器的核心接口之一,它负责管理应用程序中的 bean 并提供了各种功能。除了 ApplicationContext 接口之外,Spring 还提供了一些与其相关的子接口,这些子接口通常根据具体的使用场景和需求来扩展 ApplicationContext 的功能。
在这个类图中:
- ApplicationContext 继承了 BeanFactory,因此拥有 BeanFactory 的功能,并增加了一些额外的特性。
- ApplicationContext 还实现了 ApplicationEventPublisher、ResourceLoader、MessageSource 和 EnvironmentCapable 接口,提供了事件发布、资源加载、国际化消息处理和环境相关功能。
- ApplicationContext 中的属性包括父级 ApplicationContext、BeanFactory、事件发布器、资源加载器、消息源和环境对象。
- ApplicationContext 提供了访问这些属性的公共方法,例如获取父级 ApplicationContext、获取 BeanFactory、发布事件、获取资源加载器、获取消息源和获取环境对象等。
本文后面会针对其重要的接口和子接口进行重新的学习和总结分享。
二、ApplicationContext根接口
(一)源码展示
展示ApplicationContext 接口的部分源码,:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourceLoader {
// 获取父级 ApplicationContext
@Nullable
ApplicationContext getParent();
// 获取唯一 ID
String getId();
// 获取应用程序名称
String getApplicationName();
// 获取应用程序上下文显示名称
String getDisplayName();
// 获取启动时间
long getStartupDate();
// 获取所有 Bean 的名称
String[] getBeanDefinitionNames();
// 获取所有 Bean 的数量
int getBeanDefinitionCount();
// 检查是否包含指定名称的 Bean
boolean containsBeanDefinition(String beanName);
// 获取指定名称的 Bean 的类型
@Nullable
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
// 获取指定名称的 Bean 的别名
String[] getAliases(String name);
// 判断指定名称的 Bean 是否是单例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// 判断指定名称的 Bean 是否是原型
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
// 判断指定名称的 Bean 是否是当前上下文的 Bean
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
// 判断指定名称的 Bean 是否是指定类型的 Bean
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
// 获取指定名称的 Bean
@Nullable
<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
// 获取指定名称的 Bean
@Nullable
Object getBean(String name) throws BeansException;
// 获取指定类型的所有 Bean
<T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;
// 获取指定类型的所有 Bean 的名称
String[] getBeanNamesForType(@Nullable Class<?> type);
// 获取指定类型的所有 Bean 的名称,包括非单例 Bean
String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);
// 获取所有监听指定事件类型的监听器
<T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
throws BeansException;
// 获取指定类型的 Bean,如果有多个符合条件的 Bean,则抛出异常
<T> T getRequiredBeanOfType(@Nullable Class<T> type) throws BeansException;
// 获取指定类型的 Bean 的名称,如果有多个符合条件的 Bean,则抛出异常
String[] getBeanNamesForType(@Nullable ResolvableType type);
// 获取指定类型的 Bean,如果有多个符合条件的 Bean,则抛出异常
<T> Map<String, T> getBeansOfType(@Nullable ResolvableType type) throws BeansException;
// 获取指定类型的 Bean,如果有多个符合条件的 Bean,则抛出异常
<T> T getBean(Class<T> requiredType) throws BeansException;
// 获取指定类型的 Bean 的名称,如果有多个符合条件的 Bean,则抛出异常
String[] getBeanNamesForType(ResolvableType type);
// 获取指定类型的 Bean,如果有多个符合条件的 Bean,则抛出异常
<T> Map<String, T> getBeansOfType(ResolvableType type) throws BeansException;
// 获取指定类型的 Bean,如果有多个符合条件的 Bean,则抛出异常
<T> T getBeanProvider(Class<T> requiredType) throws BeansException;
// 是否是活跃的
boolean isActive();
}
可以从展示的部分直观的看到其定义了许多方法用于获取和操作 ApplicationContext 中的 bean。它继承了 EnvironmentCapable、ListableBeanFactory、HierarchicalBeanFactory、MessageSource、ApplicationEventPublisher 和 ResourceLoader 等接口,提供了丰富的功能来管理应用程序中的 bean,并且提供了许多便捷的方法来获取 bean 的信息。
(二)分析说明
ApplicationContext 是 Spring Framework 中的核心接口之一,其提供了一种高级的容器机制,用于管理应用程序中的组件。从上面的基本源码上,我们可以提炼出以下的基本功能分析(这里不做全面的深入,因为还是太多了):
-
Bean工厂方法: ApplicationContext 提供了丰富的方法来访问应用程序中的组件,这些方法是从 ListableBeanFactory 接口继承而来的。通过这些方法,可以方便地获取、检查和操作应用程序中的各种组件,从而实现对应用程序的灵活管理和配置。
-
加载文件资源: ApplicationContext 通过实现 ResourceLoader 接口,提供了一种通用的方式来加载文件资源。这些资源可以是位于类路径、文件系统、URL 等位置的文件,通过统一的接口可以方便地进行加载和访问,从而实现对应用程序资源的统一管理。
-
发布事件: 通过实现 ApplicationEventPublisher 接口具备了发布事件的能力,可以向注册的监听器发布事件消息,从而实现组件之间的通信和解耦。
-
解析消息和国际化支持: ApplicationContext 实现了 MessageSource 接口,支持消息的解析和国际化。通过 MessageSource,可以方便地在应用程序中实现多语言支持,根据不同的地区和语言加载相应的消息资源,从而提高了应用程序的可用性和用户体验。
-
父子上下文继承: ApplicationContext 支持从父上下文继承,子上下文中的定义优先级更高。意味着可以在整个应用程序中共享父上下文中的 bean,同时每个子上下文可以拥有自己的 bean 定义,实现更加灵活的应用程序结构。这种层级关系的管理机制使得应用程序更加模块化和可维护。
除了以上提到的功能外,ApplicationContext 还具备对应用程序中的 bean 进行生命周期管理的能力,同时可以检测和调用实现了 ApplicationContextAware、ResourceLoaderAware、ApplicationEventPublisherAware 和 MessageSourceAware 接口的 bean,使得这些 bean 可以获取对 ApplicationContext、ResourceLoader、ApplicationEventPublisher 和 MessageSource 的引用,并在运行时进行相应的操作和处理。
三、子接口ConfigurableApplicationContext
(一)源码展示
ConfigurableApplicationContext 是 ApplicationContext 接口重要的子接口,它继承了 ApplicationContext 接口,并添加了一些额外的配置功能。以下是 ConfigurableApplicationContext 接口的部分源码展示:
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
// 设置应用程序上下文的 ID
void setId(String id);
// 设置应用程序名称
void setApplicationName(String applicationName);
// 设置父级应用程序上下文
void setParent(@Nullable ApplicationContext parent);
// 添加 BeanFactoryPostProcessor,用于在 bean 工厂初始化之前对 bean 定义进行后置处理
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
// 注册一个关闭钩子,用于在 JVM 关闭时关闭应用程序上下文
void registerShutdownHook();
// 刷新应用程序上下文,启动容器并且在必要时触发 bean 工厂后置处理器和 bean 后置处理器的注册
void refresh() throws BeansException, IllegalStateException;
// 关闭应用程序上下文,释放所有资源并触发 destroy 方法
void close();
// 销毁应用程序上下文,释放所有资源
@Override
void destroy();
// 获取环境信息
@Override
ConfigurableEnvironment getEnvironment();
}
在这个接口中,可以看到一些额外的配置功能,例如设置应用程序上下文的 ID、应用程序名称、父级上下文等。另外,还提供了添加 BeanFactoryPostProcessor、注册关闭钩子、刷新和关闭应用程序上下文等方法,用于配置和管理应用程序上下文的生命周期。
注意的是,ConfigurableApplicationContext 接口继承了 Lifecycle 和 Closeable 接口,这意味着它具备了管理生命周期和关闭资源的能力。因此,任何实现了 ConfigurableApplicationContext 接口的类都应该实现这些接口中定义的方法,以确保应用程序上下文的正常运行和关闭。
(二)分析理解
ConfigurableApplicationContext 接口的设计旨在提供一种可配置的、可定制化的应用程序上下文,以满足不同场景下的需求。具体理解可以从这几个方面展开:
-
灵活的配置功能: ConfigurableApplicationContext 接口提供了一系列设置方法,如 setId、setApplicationName、setParent 等,用于对应用程序上下文进行配置。通过这些方法,可以灵活地配置应用程序上下文的各种属性,以满足不同应用场景下的需求。例如,可以为应用程序上下文设置唯一的 ID、指定应用程序的名称、设置父级上下文等。
-
后置处理器的支持: ConfigurableApplicationContext 接口提供了添加 BeanFactoryPostProcessor 的方法 addBeanFactoryPostProcessor。这意味着在应用程序上下文刷新之前,可以注册一个或多个 BeanFactoryPostProcessor,用于在 bean 工厂初始化之前对 bean 定义进行后置处理。通过这种机制,可以在容器启动之前对 bean 进行定制化的处理,例如修改 bean 的定义、添加新的 bean 定义等。
-
生命周期管理: ConfigurableApplicationContext 继承了 Lifecycle 接口,具备了管理生命周期的能力。它提供了刷新应用程序上下文的方法 refresh,用于启动容器并且在必要时触发 bean 工厂后置处理器和 bean 后置处理器的注册。另外,它还提供了关闭应用程序上下文的方法 close,用于释放所有资源并触发 destroy 方法。通过这些方法,可以对应用程序上下文的生命周期进行管理,确保容器的正常运行和关闭。
-
环境配置: ConfigurableApplicationContext 提供了获取环境信息的方法 getEnvironment,用于获取应用程序上下文的环境配置。通过环境信息,可以方便地获取应用程序的配置属性,例如配置文件中的属性、系统属性等,为应用程序的配置和定制提供了更多的灵活性和可定制性。
四、深入理解几个父接口
ConfigurableApplicationContext 是 ApplicationContext 接口重要的子接口,ApplicationContext本身还实现了几个父接口,这些父接口共同组成了ApplicationContext扩展的几个核心特性。
(一)EnvironmentCapable
EnvironmentCapable 接口的设计和实现旨在提供一种统一的方式来获取应用程序的环境配置信息,以实现组件之间的解耦合、环境配置的一致性,并且易于扩展和定制。
1.源码展示分析
EnvironmentCapable 接口定义了获取 Environment 对象的方法,是 Spring Framework 中用于获取应用程序环境配置信息的核心接口之一。以下是 EnvironmentCapable 接口的部分源码展示:
public interface EnvironmentCapable {
// 获取应用程序环境对象
Environment getEnvironment();
}
在这个接口中,只定义了一个方法 getEnvironment,用于获取应用程序的环境对象。Environment 对象提供了访问应用程序配置属性、系统属性、环境变量等环境信息的方法,使得应用程序可以方便地获取和管理这些配置信息。通过实现 EnvironmentCapable 接口并提供相应的实现,可以使得应用程序具备了获取环境配置信息的能力,从而可以根据不同的环境配置来调整应用程序的行为和功能。
2.理解其与ApplicationContext的关系
EnvironmentCapable 接口与 ApplicationContext 的关系在于 ApplicationContext 接口继承了 EnvironmentCapable 接口。这意味着任何实现了 ApplicationContext 接口的类都必须提供对环境配置信息的获取能力,即实现了 getEnvironment 方法。
ApplicationContext 接口继承了 EnvironmentCapable 接口的原因在于,Spring 应用程序上下文需要能够获取应用程序的环境配置信息,以便于在运行时根据配置信息进行相应的操作和调整。环境配置信息可能包括应用程序的属性配置、系统属性、环境变量等。通过实现 EnvironmentCapable 接口,ApplicationContext 接口承担了获取环境配置信息的责任,使得应用程序上下文具备了对环境配置的统一访问能力。
EnvironmentCapable 接口与 ApplicationContext 的关系是一种接口继承关系,它体现了 ApplicationContext 接口对环境配置信息的依赖和需求。通过这种关系,ApplicationContext 可以通过 getEnvironment 方法获取环境配置信息,从而实现了对环境配置的统一管理和访问。
3.简单的应用举例说明
我现在有个应用程序,可能会根据不同的环境配置采取不同的行动。例如,在开发环境中,可能希望连接到本地数据库,而在生产环境中,可能希望连接到远程数据库。针对这样的需求我们就可以通过使用 EnvironmentCapable 接口和 ApplicationContext,可以轻松地实现这种行为差异。
下面是一个简单的示例,演示了如何在 Spring 应用程序中使用 EnvironmentCapable 接口和 ApplicationContext 来根据不同的环境配置加载不同的数据库连接信息:
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.Environment;
public class DatabaseConfigExample {
public static void main(String[] args) {
// 根据不同的环境加载不同的配置类
ApplicationContext context = new AnnotationConfigApplicationContext(DatabaseConfig.class);
// 获取 Environment 对象
Environment environment = context.getEnvironment();
// 从环境中获取数据库连接信息
String databaseUrl = environment.getProperty("database.url");
String databaseUsername = environment.getProperty("database.username");
String databasePassword = environment.getProperty("database.password");
// 连接到数据库
System.out.println("Connecting to database:");
System.out.println("URL: " + databaseUrl);
System.out.println("Username: " + databaseUsername);
System.out.println("Password: " + databasePassword);
}
}
代码中定义了一个 DatabaseConfig 类,它根据不同的环境加载不同的数据库连接配置。然后,我们通过 ApplicationContext 获取到 Environment 对象,从中获取数据库连接信息。通过这种方式,可以根据不同的环境配置加载不同的数据库连接信息,从而实现了环境配置的灵活管理。
在实际的应用程序中,你可以将开发环境、测试环境和生产环境的配置信息分别存放在不同的配置文件中,然后通过 Spring 的配置功能来加载相应的配置文件,并根据需要获取相应的环境配置信息。这样就能够实现在不同环境下对应用程序的配置和行为进行灵活管理。
(二)MessageSource
ApplicationContext 中通常会包含一个 MessageSource 对象,用于解析和获取消息文本。通过 ApplicationContext 提供的方法,可以方便地获取 MessageSource 对象,并使用它来获取应用程序的国际化消息。这样就实现了 ApplicationContext 对国际化功能的支持和扩展。
1.源码展示分析
MessageSource 是 Spring Framework 提供的国际化支持接口,用于解析和获取消息,支持应用程序的多语言和国际化功能。以下是 MessageSource 接口的部分源码展示:
public interface MessageSource {
// 根据消息的代码和参数获取对应的消息文本
String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale) throws NoSuchMessageException;
// 根据消息的代码和参数获取对应的消息文本,如果找不到对应的消息,则返回 null
@Nullable
String getMessage(String code, @Nullable Object[] args, Locale locale);
// 根据消息的代码获取对应的消息文本,如果找不到对应的消息,则返回 null
@Nullable
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
}
MessageSource 接口的设计和实现目的在于提供一种统一的方式来解析和获取消息文本,以支持应用程序的多语言和国际化功能。通过调用 getMessage 方法并传入相应的参数,可以根据消息的代码、参数和区域设置获取对应的消息文本,从而实现应用程序的国际化支持。
2.理解应用举例说明
实现一个简单的控制器,用于处理用户登录请求,并返回相应的消息,要求使用 MessageSource 接口来实现对登录成功和失败消息的国际化支持。
首先,我们需要在 Spring 配置文件中配置 MessageSource bean,并提供相应的消息资源文件,如 messages.properties 和 messages_zh.properties。这些文件包含了登录成功和失败消息的文本,分别对应不同的语言版本。
示例 messages.properties 文件内容如下:
login.success=Login successful.
login.error=Login failed. Please check your username and password.
示例 messages_zh.properties 文件内容如下:
login.success=登录成功。
login.error=登录失败。请检查用户名和密码。
事实上,在 Spring 应用程序中,ApplicationContext 是一个全局的容器,它在应用程序启动时被加载,并负责管理各个组件的生命周期和依赖关系。我们的控制器通常会被 Spring 容器管理,而 ApplicationContext 会自动地注入到控制器中。按当前的需求简单实现代码如下:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Locale;
@Controller
public class LoginController {
@Autowired
private ApplicationContext applicationContext;
@PostMapping("/login")
@ResponseBody
public String login(@RequestParam("username") String username, @RequestParam("password") String password) {
// 假设这里进行了用户名和密码的验证
boolean isAuthenticated = authenticate(username, password);
if (isAuthenticated) {
// 获取当前请求的语言环境
Locale locale = LocaleContextHolder.getLocale();
// 从 ApplicationContext 中获取 MessageSource 对象
MessageSource messageSource = applicationContext.getBean(MessageSource.class);
// 获取登录成功消息
String successMessage = messageSource.getMessage("login.success", null, locale);
return successMessage;
} else {
// 获取当前请求的语言环境
Locale locale = LocaleContextHolder.getLocale();
// 从 ApplicationContext 中获取 MessageSource 对象
MessageSource messageSource = applicationContext.getBean(MessageSource.class);
// 获取登录失败消息
String errorMessage = messageSource.getMessage("login.error", null, locale);
return errorMessage;
}
}
private boolean authenticate(String username, String password) {
// 这里省略了用户名密码验证的逻辑,简单返回 true
return true;
}
}
(三)ApplicationEventPublisher
ApplicationContext 接口继承了 ApplicationEventPublisher 接口,这意味着 ApplicationContext 具有发布事件的能力。在 Spring 应用程序中,通常会使用 ApplicationContext 来发布事件,以实现组件之间的解耦合和通信。
事件发布是 ApplicationContext 提供的一个重要功能,它允许应用程序的各个组件在适当的时候发布自定义事件,而不需要直接依赖于其他组件。通过事件驱动的方式,可以实现应用程序的松耦合,提高了代码的灵活性和可维护性。
除了作为事件发布器之外,ApplicationContext 还可以作为事件监听器(Event Listener)的容器。在 Spring 应用程序中,我们可以将事件监听器注册到 ApplicationContext 中,然后 ApplicationContext 会自动将事件分发给注册的监听器,从而实现对事件的监听和处理。
1.源码展示分析
ApplicationEventPublisher 接口是 Spring Framework 中用于发布事件的核心接口之一。以下是 ApplicationEventPublisher 接口的部分源码展示:
public interface ApplicationEventPublisher {
// 发布事件
void publishEvent(ApplicationEvent event);
// 发布事件给指定的监听器
void publishEvent(Object event);
}
在这个接口中,包含了两个发布事件的方法:
-
publishEvent(ApplicationEvent event): 这个方法用于发布指定的应用程序事件。它接收一个 ApplicationEvent 对象作为参数,表示要发布的事件。一般情况下,我们会创建自定义的事件类,继承自 ApplicationEvent,然后通过这个方法来发布自定义事件。
-
publishEvent(Object event): 这个方法也用于发布事件,但它接收一个任意类型的对象作为参数。Spring 会根据对象的类型来确定要发布的事件。如果对象是一个 ApplicationEvent 的子类,那么 Spring 会将其视为一个应用程序事件,并按照正常的方式进行处理。否则,Spring 会将其包装成 PayloadApplicationEvent,然后发布给监听器。
ApplicationEventPublisher 接口的设计和实现目的在于提供一种统一的方式来发布事件,以实现应用程序中各个组件之间的解耦合。通过调用 publishEvent 方法,可以将自定义事件发布给应用程序中的所有监听器,从而实现事件驱动的编程模型。
2.Spring Framework 事件驱动核心组件
Spring Framework 的事件驱动核心可以划分为以下几个主要部分:
-
事件(Event): 事件是 Spring Framework 中的核心概念之一,代表着应用程序中发生的某个特定的动作或状态变化。事件通常被封装成一个 Java 类,实现了 ApplicationEvent 接口或其子类。Spring 提供了 ApplicationEvent 接口以及一些预定义的事件类,同时也支持开发者自定义事件类。
-
事件发布器(Event Publisher): 事件发布器是 Spring Framework 中用于发布事件的组件。在 Spring 中,事件发布器由 ApplicationEventPublisher 接口来定义它通常由 ApplicationContext 实现。通过事件发布器,应用程序可以将事件发布到应用程序上下文中,以便监听器能够捕获并处理这些事件。
-
事件监听器(Event Listener): 事件监听器是 Spring Framework 中用于监听和处理事件的组件。在 Spring 中,事件监听器由 ApplicationListener 接口来定义,开发者可以实现这个接口来定义自己的事件监听器。事件监听器监听特定类型的事件,当事件发生时,监听器会被调用,并执行相应的处理逻辑。
-
事件多播器(Event Multicaster): 事件多播器是 Spring Framework 中用于将事件分发给多个监听器的组件。在 Spring 中,事件多播器由 ApplicationEventMulticaster 接口来定义,通常由 AbstractApplicationContext 实现。它负责将事件传递给所有注册的监听器,并确保它们按照特定的顺序进行调用。
-
事件源(Event Source): 事件源是指触发事件的对象或组件。在 Spring 中,事件源通常是 ApplicationContext 或其他的 Spring Bean。当事件发生时,事件源会将事件传递给事件多播器,然后由多播器将事件分发给相应的监听器。
3.
(四)ResourcePatternResolver
(五)ResourcePatternResolver
四、
源码或官方文章
https://docs.spring.io/spring-framework/reference/core/beans/context-introduction.html
Container Overview :: Spring Framework
Spring Framework Documentation :: Spring Framework
Java-based Container Configuration :: Spring Framework