1. 概述
本文,我们来补充 《精尽 Spring Boot 源码分析 —— SpringApplication》 文章,并未详细解析的 ApplicationListener 。
2. ApplicationListener
org.springframework.context.ApplicationListener
,应用事件监听器接口。代码如下:
// ApplicationListener.java /** * Interface to be implemented by application event listeners. * Based on the standard {@code java.util.EventListener} interface * for the Observer design pattern. * * <p>As of Spring 3.0, an ApplicationListener can generically declare the event type * that it is interested in. When registered with a Spring ApplicationContext, events * will be filtered accordingly, with the listener getting invoked for matching event * objects only. * * @author Rod Johnson * @author Juergen Hoeller * @param <E> the specific ApplicationEvent subclass to listen to * @see org.springframework.context.event.ApplicationEventMulticaster */ public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); } |
- 如果对这块不了解的胖友,可以看看 《Spring 5 源码解析 —— Spring 框架中的事件和监听器》 文章。
2.1 SmartApplicationListener
org.springframework.context.event.SmartApplicationListener
接口,实现 ApplicationListener、Ordered 接口,是 Spring3.0 新增的接口,提供了事件类型和来源的判断接口方法。代码如下:
// SmartApplicationListener.java /** * Extended variant of the standard {@link ApplicationListener} interface, * exposing further metadata such as the supported event and source type. * * <p>For full introspection of generic event types, consider implementing * the {@link GenericApplicationListener} interface instead. * * @author Juergen Hoeller * @since 3.0 * @see GenericApplicationListener * @see GenericApplicationListenerAdapter */ public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered { /** * 事件类型 * Determine whether this listener actually supports the given event type. * @param eventType the event type (never {@code null}) */ boolean supportsEventType(Class<? extends ApplicationEvent> eventType); /** * 事件来源 * Determine whether this listener actually supports the given source type. * <p>The default implementation always returns {@code true}. * @param sourceType the source type, or {@code null} if no source */ default boolean supportsSourceType(@Nullable Class<?> sourceType) { return true; } /** * Determine this listener's order in a set of listeners for the same event. * <p>The default implementation returns {@link #LOWEST_PRECEDENCE}. */ default int getOrder() { return LOWEST_PRECEDENCE; } } |
2.1 GenericApplicationListener
org.springframework.context.event.GenericApplicationListener
,继承 ApplicationListener、Ordered 接口,是 Spring4.2 新增的接口,它增强了对泛型的支持,#supportsEventType(ResolvableType)
方法的参数采用的是可解析类型 ResolvableType 。代码如下:
ResolvableType是 Spring4 提供的泛型操作支持类,通过它可以很容易地获得泛型的实际类型信息,比如类级、字段级等等泛型信息。在 Spring4 的框架中,很多核心类内部涉及的泛型操作大都使用 ResolvableType 类进行处理。
// GenericApplicationListener.java /** * Extended variant of the standard {@link ApplicationListener} interface, * exposing further metadata such as the supported event and source type. * * <p>As of Spring Framework 4.2, this interface supersedes the Class-based * {@link SmartApplicationListener} with full handling of generic event types. * * @author Stephane Nicoll * @since 4.2 * @see SmartApplicationListener * @see GenericApplicationListenerAdapter */ public interface GenericApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered { /** * 事件类型【有变动】 * Determine whether this listener actually supports the given event type. * @param eventType the event type (never {@code null}) */ boolean supportsEventType(ResolvableType eventType); /** * 事件来源 * Determine whether this listener actually supports the given source type. * <p>The default implementation always returns {@code true}. * @param sourceType the source type, or {@code null} if no source */ default boolean supportsSourceType(@Nullable Class<?> sourceType) { return true; } /** * Determine this listener's order in a set of listeners for the same event. * <p>The default implementation returns {@link #LOWEST_PRECEDENCE}. */ default int getOrder() { return LOWEST_PRECEDENCE; } } |
3. SpringApplication 中的使用
在 SpringApplication 构造方法中,会调用 #getSpringFactoriesInstances(Class<T> type)
方法,获得 ApplicationListener 集合。代码如下:
// SpringApplication.java private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) { return getSpringFactoriesInstances(type, new Class<?>[] {}); } private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = getClassLoader(); // Use names and ensure unique to protect against duplicates // <1> 加载指定类型对应的,在 `META-INF/spring.factories` 里的类名的数组 Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // <2> 创建对象们 List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); // <3> 排序对象们 AnnotationAwareOrderComparator.sort(instances); return instances; } |
-
<1>
处,加载指定 ApplicationListener 类型对应的,在META-INF/spring.factories
里的类名的数组。- 假设只在 Spring MVC 的环境下,
listeners
属性的结果如下图: - 艿艿整理了 Spring Boot 中,ApplicationContextInitializer 的实现类们,非常多。本文,我们就分享上述的 10 个。
- 假设只在 Spring MVC 的环境下,
-
<2>
处,创建对象们。 -
<3>
处,排序对象们。
4. ConfigFileApplicationListener
org.springframework.boot.context.config.ConfigFileApplicationListener
,实现 SmartApplicationListener、Ordered、EnvironmentPostProcessor 接口,实现 Spring Boot 配置文件的加载。
考虑到它非常重要,且复杂,我们单独在 《精尽 Spring Boot 源码分析 —— 配置加载》 详细解析。
5. AnsiOutputApplicationListener
org.springframework.boot.context.config.AnsiOutputApplicationListener
,实现 ApplicationListener、Ordered 接口,在 Spring Boot 环境变量(environment
)准备完成以后运行,
如果你的终端支持 ANSI ,设置彩色输出会让日志更具可读性。
不了解“彩色输出”的胖友,可以看看 《Spring Boot日志管理》 文章。
代码如下:
// ConfigFileApplicationListener.java public class AnsiOutputApplicationListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered { public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) { // <1> // if (true) { // return; // <X> // } ConfigurableEnvironment environment = event.getEnvironment(); // <2> 根据环境变量 spring.output.ansi.enabled 的值,设置 AnsiOutput.enabled 属性 Binder.get(environment).bind("spring.output.ansi.enabled", AnsiOutput.Enabled.class) .ifBound(AnsiOutput::setEnabled); // <3> 根据环境变量 "spring.output.ansi.console-available 的值,设置 AnsiOutput.consoleAvailable 属性 AnsiOutput.setConsoleAvailable(environment.getProperty("spring.output.ansi.console-available", Boolean.class)); } public int getOrder() { // Apply after ConfigFileApplicationListener has called EnvironmentPostProcessors return ConfigFileApplicationListener.DEFAULT_ORDER + 1; } } |
-
<1>
处,我们可以知道,监听的是 ApplicationEnvironmentPreparedEvent 事件。 -
<2>
处,根据环境变量"spring.output.ansi.enabled"
的值,设置AnsiOutput.enabled
属性。这块的逻辑,卡了艿艿很久,一点一点来说。-
首先,因为艿艿并没有细看 Binder 的实现代码,所以这块就卡了一会。简单来说,
Binder.get(environment).bind("spring.output.ansi.enabled", AnsiOutput.Enabled.class)
代码块的意思是,从environment
读取"spring.output.ansi.enabled"
对应的值,并转换成 AnsiOutput.Enabled 类型。其中,AnsiOutput.Enabled 的枚举值如下:// AnsiOutput#Enabled.java public enum Enabled { /** * 自动探测,根据是否支持 ANSI 的功能,来判断是否要彩色输出 * * 【默认值】 * * Try to detect whether ANSI coloring capabilities are available. The default * value for {@link AnsiOutput}. */ DETECT, /** * 总是开启 ANSI 彩色输出 * * Enable ANSI-colored output. */ ALWAYS, /** * 禁用 ANSI 彩色输出 * * Disable ANSI-colored output. */ NEVER }
-
貌似也没什么问题。但是,让艿艿闷逼的是,为什么结果会是
AnsiOutput.Enabled.ALWAYS
,在 IDEA 环境中。后来,在environment
中,一个名字是"systemProperties"
的 MapPropertySource 属性源,里面提供了"spring.output.ansi.enabled=always"
的配置。- 各种全文检索代码,貌似除了测试用例里,没有地方强制赋值了
"spring.output.ansi.enabled"
。 - 后来发现,
"systemProperties"
这个 MapPropertySource 属性源,读取的是System#getProperties()
方法,但是为啥里面会有"spring.output.ansi.enabled=always"
呢?目前的猜测是,IDEA 判断在 Spring Boot 环境下,自动添加进去的!- 然后,
.ifBound(AnsiOutput::setEnabled)
代码段,应该翻译成如下的代码,可能比较易懂:Binder.get(environment).bind("spring.output.ansi.enabled", AnsiOutput.Enabled.class) .ifBound(new Consumer<Enabled>() { public void accept(Enabled enabled) { AnsiOutput.setEnabled(enabled); } });
- 然后,
- 各种全文检索代码,貌似除了测试用例里,没有地方强制赋值了
-
即,
Binder.get(environment).bind("spring.output.ansi.enabled", AnsiOutput.Enabled.class)
返回的是 BindResult 对象,然后调用BindResult#ifBound(Consumer)
方法,将解析到的属性值,赋值到AnsiOutput.enabled
属性。
-
-
相关推荐
labview程序代码参考学习使用,希望对你有所帮助。
毕设和企业适用springboot生鲜鲜花类及数据处理平台源码+论文+视频.zip
毕设和企业适用springboot企业数据智能分析平台类及汽车管理平台源码+论文+视频
毕设和企业适用springboot社区物业类及企业创新研发平台源码+论文+视频
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Floating Text Example</title> <style> .floating-text { font-size: 24px; position: relative; animation: float 3s ease-in-out infinite; } @keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-20px); } } </style> </head> <body> <div class="floating-text">Hello, I'm floating!</div> <script> document.addEventListener('DOMContentLoaded', function() {
毕设和企业适用springboot社交媒体分析平台类及智慧医疗管理平台源码+论文+视频
毕设和企业适用springboot生鲜鲜花类及餐饮管理平台源码+论文+视频
毕设和企业适用springboot人工智能客服系统类及用户行为分析平台源码+论文+视频
毕设和企业适用springboot全渠道电商平台类及个性化广告平台源码+论文+视频
毕设和企业适用springboot社交互动平台类及线上图书馆源码+论文+视频
毕设和企业适用springboot企业知识管理平台类及供应链优化平台源码+论文+视频
毕设和企业适用springboot企业健康管理平台类及数据处理平台源码+论文+视频.zip
内容概要:本文档是一份面向初学者的详细指南,重点介绍如何利用Vue.js 2.0快速创建和运行简单的Todo List应用。首先指导安装必需的Node.js、npm/yarn等环境准备,接着通过Vue CLI工具生成新的Vue项目,再详细介绍项目目录和组件的构建方式。最后提供了具体的方法实现添加和删除待办事项,并指导如何使用命令启动应用,查看结果。 适合人群:具备基础Web开发技能的前端开发新手,尤其是对Vue框架感兴趣的学习者。 使用场景及目标:作为初学者入门级的学习资料,本文档的目标是让读者能够在最短时间内掌握Vue.js的基础概念和技术栈的应用方式,以便日后可以独立地构建更加复杂的Vue应用。 其他说明:除了学习如何构建应用程序之外,本文档还涵盖了Vue的基本语法和数据绑定、事件处理机制等重要概念,对于理解Vue框架的工作原理十分有帮助。
毕设和企业适用springboot企业健康管理平台类及智能化系统源码+论文+视频.zip
毕设和企业适用springboot企业健康管理平台类及远程医疗平台源码+论文+视频.zip
毕设和企业适用springboot数据可视化类及数据智能化平台源码+论文+视频
毕设和企业适用springboot生鲜鲜花类及用户体验优化平台源码+论文+视频.zip
毕设和企业适用springboot人工智能客服系统类及虚拟银行平台源码+论文+视频
毕设和企业适用springboot社交应用平台类及云计算资源管理平台源码+论文+视频
毕设和企业适用springboot企业数据监控平台类及线上图书馆源码+论文+视频