(二) springBoot 初始化器和监听器
系统初始化器介绍:
类名:ApplicationContextInitializer ; 介绍:spring容器刷新之前执行的一个回调函数; 作用:向springBoot容器注册属性; 也可以自定义初始化器来修改env, springcloud获取远程配置就是采用这个方式。使用方式:继承接口自定义实现。自定义初始化器实现的三种方式:
1 实现ApplicationContextInitializer接口,重写initialize方法。在SpringApplication类初始化后通过其addInitializers()方法设置进去。
2 实现ApplicationContextInitializer接口,重写initialize方法。spring.factories内填写接口实现,key值为org.springframework.context.ApplicationContextInitializer接口。
3 实现ApplicationContextInitializer接口,重写initialize方法。在application.properties内填写接口实现,key值为context.initializer.classes
以上三种实现方式都需要实现ApplicationContextInitializer接口,重写initialize方法。他们的运行顺序按order进行执行,order值越小越先执行,但是在application.properties内定义的优先于其它方式。
添加初始化器流程:
SpringFactoriesLoader介绍:
SpringFactoriesLoader工厂加载机制是 Spring 内部提供的一个约定俗成的加载方式,与 java spi 类似,只需要在模块的 META-INF/spring.factories 文件中,以 Properties 类型(即 key-value 形式)配置,就可以将相应的实现类注入 Spirng 容器中. properties的文件内容必须是kv形式,key是全限定名(抽象 | 接口) value是实现,多个实现用","分割。
SpringFactoriesLoader加载自定义初始化器如下图所示:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = getClassLoader(); // 保存结果到缓存 Set<String> names = new LinkedHashSet<>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 通过反射实例化类
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 对结果对象进行排序 AnnotationAwareOrderComparator.sort(instances); return instances; }
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { String factoryClassName = factoryClass.getName();
//加载并获取指定key对应的value return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); } private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) { return result; } // 读取指定资源配置文件 String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
try { Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url);
//构造properties Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry<?, ?> entry : properties.entrySet()) { String factoryClassName = ((String) entry.getKey()).trim(); for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { result.add(factoryClassName, factoryName.trim()); } } } cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }
应用初始化器源码:
//类 SpringApplication
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
详情可参考:SpringFactoriesLoader详解(https://blog.csdn.net/zs18753479279/article/details/116404217)
事件监听器:
监听模式:springBoot的事件监听,是观察者模式的一种应用。当系统有重大事件发生时,会通过广播器将事件发出,而系统的部分监听器是对一些事件感兴趣的,当这部分事件被发布出来后,监听器会监听到,从而触发一些动作。
监听器四要素:监听器、广播器、监听事件、监听事件触发机制
springBoot的事件发布是在run方法中实现的,首先通过SpringApplicationRunListeners listeners = getRunListeners(args)方法获得用于发射SpringBoot启动过程中的各种生命周期事件的对象SpringApplicationRunListeners,而getRunListeners方法内部会利用SPI机制,通过getSpringFactoriesInstance方法把SpringApplicationRunListener的实现类EventPublishingRunListener加载进来。
1 2 3 4 5 | private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication. class , String[]. class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( SpringApplicationRunListener. class , types, this , args)); } |
SpringApplicationRunListeners是如何发射事件的呢?
其实SpringApplicationRunListeners
对象没有承担广播事件的职责,而最终是委托EventPublishingRunListener来广播事件的。那么广播的事件从哪里来?
当从
可以看到在spring.factories
中加载出EventPublishingRunListener
类后会实例化,而实例化必然会通过EventPublishingRunListener
的构造函数来进行实例化,从下面的源码EventPublishingRunListener
的构造函数中有一个for
循环会遍历之前从spring.factories
中加载的监听器,然后添加到集合中缓存起来,用于以后广播各种事件时直接从这个集合中取出来即可,而不用再去spring.factories
中加载,提高效率。
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered { private final SpringApplication application; private final String[] args; private final SimpleApplicationEventMulticaster initialMulticaster; public EventPublishingRunListener(SpringApplication application, String[] args) { this.application = application; this.args = args; // 新建一个事件广播对象 this.initialMulticaster = new SimpleApplicationEventMulticaster(); for (ApplicationListener<?> listener : application.getListeners()) { // 将从spring.factories配置文件中获取获取的监听器加入到事件广播器的缓存之中 this.initialMulticaster.addApplicationListener(listener); } } @Override public int getOrder() { return 0; } @Override public void starting() { this.initialMulticaster.multicastEvent( new ApplicationStartingEvent(this.application, this.args)); } @Override public void environmentPrepared(ConfigurableEnvironment environment) { this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent( this.application, this.args, environment)); } @Override public void contextPrepared(ConfigurableApplicationContext context) { this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent( this.application, this.args, context)); } @Override public void contextLoaded(ConfigurableApplicationContext context) { for (ApplicationListener<?> listener : this.application.getListeners()) { if (listener instanceof ApplicationContextAware) { ((ApplicationContextAware) listener).setApplicationContext(context); } context.addApplicationListener(listener); } this.initialMulticaster.multicastEvent( new ApplicationPreparedEvent(this.application, this.args, context)); } @Override public void started(ConfigurableApplicationContext context) { context.publishEvent( new ApplicationStartedEvent(this.application, this.args, context)); } @Override public void running(ConfigurableApplicationContext context) { context.publishEvent( new ApplicationReadyEvent(this.application, this.args, context)); } @Override public void failed(ConfigurableApplicationContext context, Throwable exception) { ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception); if (context != null && context.isActive()) { // Listeners have been registered to the application context so we should // use it at this point if we can context.publishEvent(event); } else { // An inactive context may not have a multicaster so we use our multicaster to // call all of the context's listeners instead if (context instanceof AbstractApplicationContext) { for (ApplicationListener<?> listener : ((AbstractApplicationContext) context) .getApplicationListeners()) { this.initialMulticaster.addApplicationListener(listener); } } this.initialMulticaster.setErrorHandler(new LoggingErrorHandler()); this.initialMulticaster.multicastEvent(event); } } private static class LoggingErrorHandler implements ErrorHandler { private static Log logger = LogFactory.getLog(EventPublishingRunListener.class); @Override public void handleError(Throwable throwable) { logger.warn("Error calling ApplicationEventListener", throwable); } } }
springBoot启动过程中会调用spingApplicationRunListeners的如下方法发布事件

以发送starting事件为例来说明一下发布事件,到执行listener的具体方法为例:
发送事件的场景分别如下:
a 框架在刚启动的时候会发送一个starting事件
b 在环境准备好的时候(把一些系统属性与自定义属性加载到了容器中)会发送environmentPrepared事件
c 在当应用上下文(ApplicationContext)准备好了,并且应用初始化器(ApplicationContextInitializers)已经被调用,在 bean 的定义(bean definitions)被加载之前发送contextInitinized事
d Spring 上下文(context)刷新之前,且在 bean 的定义(bean definitions)被加载之后发送contextPrepared事件
e Spring 上下文(context)刷新之后,单例Bean实例化完成,且在 application/ command-line runners 被调用之前发送started事件。
f 在任何 application/ command-line runners 调用之后发送ready事件。

1 实现ApplicationListener接口,spring.factories内填写接口实现,key值为org.springframework.context.ApplicationListener
2 实现ApplicationListener接口,通过springApplication的addListeners方法加入进去
3 实现ApplicationListener接口,application.properties内填写接口实现,key值为org.springframework.context.ApplicationListener
4 实现SmartApplicationListener接口,重写supportEventType方法与onApplicationEvent方法,同之前三种方式注入框架
总结:
SpringBoot的初始化器与监听器都是通过SpringFactoriesLoader加载的,其原理是利用JAVA的SPI机制,去META-INF/spring.factories加载对应的接口实现类。初始化器在准备上下文prepareContext时执行。监听器是执行run方法的时候通过springRunApplicationListener触发,然后委托给实现类eventPlublisingRunListener,由这个事件广播器广播一个事件,进而调用与该事件类型匹配的监听器的回调方法,最后监听器执行onApplicationEvent方法完成监听器的响应。
springBoot的Bean:
xml文件配置方式:
1 无参构造:属性需要有set方法,xml property配置属性值
2 有参构造:参数通过constructor-arg属性配置
3静态工厂方法:xml class属性指定静态工厂类,factory-method指定工厂方法
4实例工厂方法:xml factory-bean指定工厂实例,factory-method指定工厂方法。
注解配置方式:
1 @Compent声明
2 配置类中使用@Bean
@Configuration public class BeanConfiguration{ @Bean("dog") Animal getDog() { return new Dog(); } }
3 继承FactoryBean,重写getObjects方法与getObjectType方法
@Component public class MyCat implements FactoryBean<Animal> { @Override public Animal getObject() throws Exception { return new Cat(); } @Override public Class<?> getObjectType() { return Animal.class; } }
4 实现BeanDefinitionRegistryPostProcessor接口,重写postProcessBeanDefinitionRegistry与postProcessBeanFactory方法
@Component public class MyBeanRegister implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(); rootBeanDefinition.setBeanClass(Monkey.class); registry.registerBeanDefinition("monkey", rootBeanDefinition); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { } }
public class Monkey extends Animal { @Override String getName() { return "monkey"; } }
5 实现ImportBeanDefinitionRegistrar接口,重写registerBeanDefinitions方法
public class MyBeanImport implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(); rootBeanDefinition.setBeanClass(Bird.class); registry.registerBeanDefinition("bird", rootBeanDefinition); } }
springBoot Aware介绍
Spring框架优点:Bean感知不到容器的存在
使用场景:需要使用spring容器的功能资源
引入缺点:容器和bean强耦合
常用Aware:
类名 | 作用 |
BeanNameAware |
获得容器中bean的名称 |
BeanClassLoaderAware | 获得类加载器 |
BeanFactoryAware | 获得bean创建工厂 |
EnvironmentAware | 获得环境变量 |
EmbeddedValueResolverAware | 获取spring容器加载的properties文件属性值 |
ResourcedLoaderAware | 获得资源加载器 |
ApplicationEventPublisherAware | 获得应用事件发布器 |
MessageSourceAware |
获得文本信息 |
ApplicationContextAware | 获得当前应用上下文 |
springBoot启动加载器:
@Component @Order(1) public class FirstApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { System.out.println("\u001B[32m >>> startup first application runner<<<"); } }
@Component @Order(1) public class FirstCommandlineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("\u001B[32m >>> startup first runner<<<"); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix