Spring Boot 监听器详解

news2024/11/26 3:27:22

Spring Boot 3.x系列文章

  1. Spring Boot 2.7.8 中文参考指南(一)
  2. Spring Boot 2.7.8 中文参考指南(二)-Web
  3. Spring Boot 源码阅读初始化环境搭建
  4. Spring Boot 框架整体启动流程详解
  5. Spring Boot 系统初始化器详解
  6. Spring Boot 监听器详解

监听器的介绍

通过前面的几篇文章,我们都能看到SpringApplicationRunListener,SpringApplicationRunListener 是SpringApplication 的运行监听器,提供Spring Boot启动时各个运行状态的监听,可以在应用程序启动的时候执行一些自定义操作或记录一些信息。SpringApplicationRunListener 在run中加载SpringApplicationRunListeners listeners = getRunListeners(args);
ApplicationListener是Spring 提供的上下文监听器,可用于监听指定感兴趣的事件。

监听器的使用

SpringApplicationRunListener

SpringApplicationRunListener 的使用比较简单,实现该接口,并在META-INF/spring.factories中定义该实现

MyApplicationRunListener.java

public class MyApplicationRunListener implements SpringApplicationRunListener {

    @Override
    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        System.out.println("Application 启动");
    }

    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
        System.out.println("环境已准备完毕");
    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("在创建和准备ApplicationContext之后,但在加载源之前调用");
    }

    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("上下文准备完毕,未刷新");
    }

    @Override
    public void started(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("上下文已刷新,应用程序已启动,但尚未调用CommandLineRunners和ApplicationRunners");
    }

    @Override
    public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("在刷新应用程序上下文并且调用了所有CommandLineRunner和ApplicationRunner之后,在运行方法完成之前立即调用");
    }

    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("当运行应用程序时发生故障时调用");
    }
}

META-INF/spring.factories

org.springframework.boot.SpringApplicationRunListener=com.springboot.demo.listeners.MyApplicationRunListener

运行情况:
在这里插入图片描述

ApplicationListener

1、实现ApplicationListener接口

MyApplicationListener.java

@Slf4j
public class MyApplicationListener implements ApplicationListener<ApplicationStartedEvent> {

    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        log.info("应用启动完成");
    }
}

META-INF/spring.factories

org.springframework.context.ApplicationListener=com.springboot.demo.listeners.MyApplicationListener

2、addListener

在springApplication 中添加,同样达到效果

SpringApplication springApplication = new SpringApplication(SpringBootDemoApplication.class);
springApplication.addListeners(new MyApplicationListener());

3、context.istener.classes

在配置文件中添加该配置,value为MyApplicationListener的全路径限定名

context:
  listener:
    classes: com.springboot.demo.listeners.MyApplicationListener

4、@EventListener

该注解是spring 提供的方式,支持同时监听多种事件,支持SpEL表达式

@Component
@Slf4j
public class MyApplicationListener2 {

    //监听单个事件
    @EventListener
    public void listenerApplicationStarted(ApplicationStartedEvent event) {
        log.info("应用启动完成");
    }
    
    @EventListener({ApplicationEnvironmentPreparedEvent.class})
    public void listenerApplicationEnv() {
        //实际测试,没有监听到,后面说明原理
        log.info("监听到了环境准备完成事件");
    }
    
    //监听多个事件
    @EventListener({ApplicationReadyEvent.class, ApplicationStartedEvent.class})
    public void listenerApplication() {
        log.info("监听到了多个事件");
    }

    //自己发布了一个Person事件,Person并没有继承ApplicationEvent
    @EventListener
    public void myCustomListener(Person person) {
        log.info("监听到自己发布的事件,{}", person);
    }

    //只有Person事件中name属性值为csdn时才接收到
    @EventListener(condition = "#person.name == 'csdn'")
    public void myCustomListener2(Person person) {
        log.info("SpEL表达式监听到自己发布的事件,{}", person);
    }
}

原理解析

SpringApplicationRunListener 的原理在之前的文章都有体现,可以查看《Spring Boot 框架整体启动流程详解》,我们只需要关注ApplicationListener。

Spring Boot 中不同的使用方式有不同的加载,我们一个个来分析。

1、从spring.factories中加载

首先Spring Boot 会在SpringApplication初始化的时候从META-INF/spring.factories中加载ApplicationListener的实现,并保存在private List<ApplicationListener<?>> listeners;中,待后续使用。
在这里插入图片描述

第二个关键是EventPublishingRunListener,在run方法中通过SpringApplicationRunListeners listeners = getRunListeners(args);加载,getRunListeners 从 spring.factories加载SpringApplicationRunListener的实现保存在SpringApplicationRunListeners内部,其相当于是代理器,Spring Boot 内部只定义了一个EventPublishingRunListener实现。
在这里插入图片描述
在Spring Boot 中在不同的阶段调用不同的SpringApplicationRunListeners方法,如图只是部分
在这里插入图片描述
starting为例,会在SpringApplicationRunListeners内部通过循环前期加载的SpringApplicationRunListener实现,此处只需要关注EventPublishingRunListener
在这里插入图片描述
进入EventPublishingRunListenerstarting方法中,starting调用同类的multicastInitialEvent,事件定义为ApplicationStartingEvent

private void multicastInitialEvent(ApplicationEvent event) {
	refreshApplicationListeners();
	this.initialMulticaster.multicastEvent(event);
}

refreshApplicationListeners 会从SpringApplication保存的listeners中读取初始化时加载的ApplicationListener实现,并添加到SimpleApplicationEventMulticaster的内部类DefaultListenerRetriever中,待后续使用。

private void refreshApplicationListeners() {
		this.application.getListeners().forEach(this.initialMulticaster::addApplicationListener);
	}

第三个关键是SimpleApplicationEventMulticasterthis.initialMulticaster.multicastEvent(event) 调用到了SimpleApplicationEventMulticaster中,multicastEvent又调用了一个同名方法。

public void multicastEvent(ApplicationEvent event) {
	multicastEvent(event, null);
}

@Override
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
	//获取事件类的类型信息
	ResolvableType type = (eventType != null ? eventType : ResolvableType.forInstance(event));
	// 获取执行事件的线程池,如果设置了,可以异步执行
	Executor executor = getTaskExecutor();
	//获取指定事件类型的监听器集合
	for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
	//如果定义了执行线程池,则用线程池调用
		if (executor != null) {
			executor.execute(() -> invokeListener(listener, event));
		}
		else {
		//同步调用监听器
			invokeListener(listener, event);
		}
	}
}

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
//获取失败处理器
	ErrorHandler errorHandler = getErrorHandler();
	if (errorHandler != null) {
		try {
			doInvokeListener(listener, event);
		}
		catch (Throwable err) {
			errorHandler.handleError(err);
		}
	}
	else {
		doInvokeListener(listener, event);
	}
}

@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
	try {
	//此处执行事件监听器的onApplicationEvent方法
		listener.onApplicationEvent(event);
	}
	catch (ClassCastException ex) {
		String msg = ex.getMessage();
		if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||
				(event instanceof PayloadApplicationEvent payloadEvent &&
						matchesClassCastMessage(msg, payloadEvent.getPayload().getClass()))) {
			// Possibly a lambda-defined listener which we could not resolve the generic event type for
			// -> let's suppress the exception.
			Log loggerToUse = this.lazyLogger;
			if (loggerToUse == null) {
				loggerToUse = LogFactory.getLog(getClass());
				this.lazyLogger = loggerToUse;
			}
			if (loggerToUse.isTraceEnabled()) {
				loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
			}
		}
		else {
			throw ex;
		}
	}
}

实际上到这里流程已经走完了,最后listener.onApplicationEvent(event);调用到自定义的MyApplicationListener中。

对于如何获取指定事件类型的监听器集合,getApplicationListeners(event, type),代码比较复杂,可看也可不看。

getApplicationListeners 方法在SimpleApplicationEventMulticaster 的父类AbstractApplicationEventMulticaster中,传入传播的事件类bean和事件的类型信息。

protected Collection<ApplicationListener<?>> getApplicationListeners(
		ApplicationEvent event, ResolvableType eventType) {

	//获取事件发生的对象
	Object source = event.getSource();
	Class<?> sourceType = (source != null ? source.getClass() : null);
	//根据事件的类型信息和源对象组成一个监听器的缓存key
	ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

	// 创建一个新的监听器检索缓存
	CachedListenerRetriever newRetriever = null;

	// 根据key从检索缓存中获取缓存的监听器封装类
	CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
	//如果不存在
	if (existingRetriever == null) {
		//判断事件类型和源对象能否用指定的classLoader加载
		// 创建并缓存一个新的ListenerRetriever
		if (this.beanClassLoader == null ||
				(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
						(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
			newRetriever = new CachedListenerRetriever();
			//如果指定键没有关联值,则存入新值,返回null,有关联值返回关联值
			existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
			//有关联值,就不填充新值,将创建的对象取消关联
			if (existingRetriever != null) {
				newRetriever = null;  
			}
		}
	}

	//缓存检索器中有值,就返回缓存的事件监听器列表
	if (existingRetriever != null) {
		Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
		if (result != null) {
			return result;
		}
	}
	//缓存检索器中没有值的话,继续检索
	return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
		ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) {

	List<ApplicationListener<?>> allListeners = new ArrayList<>();
	Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);
	Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);

	Set<ApplicationListener<?>> listeners;
	Set<String> listenerBeans;
	//从默认检索器中读取监听器列表和监听器bean名称
	synchronized (this.defaultRetriever) {
		listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
		listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
	}

	// 循环添加已经注册的监听器,包括ApplicationListenerDetector加载的监听器
	for (ApplicationListener<?> listener : listeners) {
	//检查指定的监听器是否是需要关注的事件
		if (supportsEvent(listener, eventType, sourceType)) {
			if (retriever != null) {
				filteredListeners.add(listener);
			}
			allListeners.add(listener);
		}
	}

	// 通过bean名称来添加监听器,可能与上面的方式重叠,但这里会有一些新的元数据
	if (!listenerBeans.isEmpty()) {
	//获取bean工厂
		ConfigurableBeanFactory beanFactory = getBeanFactory();
		for (String listenerBeanName : listenerBeans) {
			try {
			//判断指定的监听器bean是否是需要关注的事件
				if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
				//获取监听器bean
					ApplicationListener<?> listener =
							beanFactory.getBean(listenerBeanName, ApplicationListener.class);
							//最终判断
					if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
						if (retriever != null) {
							if (beanFactory.isSingleton(listenerBeanName)) {
								filteredListeners.add(listener);
							}
							else {
								filteredListenerBeans.add(listenerBeanName);
							}
						}
						allListeners.add(listener);
					}
				}
				else {
					// 移除不支持的监听器
					Object listener = beanFactory.getSingleton(listenerBeanName);
					if (retriever != null) {
						filteredListeners.remove(listener);
					}
					allListeners.remove(listener);
				}
			}
			catch (NoSuchBeanDefinitionException ex) {
				
			}
		}
	}

	//排序
	AnnotationAwareOrderComparator.sort(allListeners);
	if (retriever != null) {
		if (filteredListenerBeans.isEmpty()) {
			retriever.applicationListeners = new LinkedHashSet<>(allListeners);
			retriever.applicationListenerBeans = filteredListenerBeans;
		}
		else {
			retriever.applicationListeners = filteredListeners;
			retriever.applicationListenerBeans = filteredListenerBeans;
		}
	}
	return allListeners;
}

看下最终判断的部分:supportsEvent(listener, eventType, sourceType)

protected boolean supportsEvent(
		ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {

	GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener gal ? gal :
			new GenericApplicationListenerAdapter(listener));
			//通过判断给定的事件类型是否与要关注的事件类型一致,并且支持给定的源类型
	return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}

这里会将监听器包装成GenericApplicationListenerAdapter,在构造器中解析出监听器关注的事件类型信息。

public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) {
	Assert.notNull(delegate, "Delegate listener must not be null");
	this.delegate = (ApplicationListener<ApplicationEvent>) delegate;
	//解析出事件类型信息
	this.declaredEventType = resolveDeclaredEventType(this.delegate);
}
public boolean supportsEventType(ResolvableType eventType) {
//如果是GenericApplicationListener 的实现,它扩展了SmartApplicationListener
	if (this.delegate instanceof GenericApplicationListener gal) {
		return gal.supportsEventType(eventType);
	}
	//如果是SmartApplicationListener的实现
	else if (this.delegate instanceof SmartApplicationListener sal) {
		Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
		return (eventClass != null && sal.supportsEventType(eventClass));
	}
	else {
	//其他类型判断
		return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
	}
}

@Override
public boolean supportsSourceType(@Nullable Class<?> sourceType) {
	return (!(this.delegate instanceof SmartApplicationListener sal) || sal.supportsSourceType(sourceType));
}

2、addListener

由于addListener是在run方法执行之前就添加到了SpringApplication中,所以加载原理同第一种方式相同

3、context.listener.classes

该配置的监听器,由Spring Boot 内置的DelegatingApplicationListener处理,该监听器定义在Spring Boot Jar包的META-INF/spring.factories中。

public void onApplicationEvent(ApplicationEvent event) {
	//环境准备完毕
	if (event instanceof ApplicationEnvironmentPreparedEvent preparedEvent) {
	//从context.listener.classes加载配置的事件监听器
		List<ApplicationListener<ApplicationEvent>> delegates = getListeners(preparedEvent.getEnvironment());
		if (delegates.isEmpty()) {
			return;
		}
		//新创建一个SimpleApplicationEventMulticaster,跟以前用的不是同一个
		this.multicaster = new SimpleApplicationEventMulticaster();
		for (ApplicationListener<ApplicationEvent> listener : delegates) {
			this.multicaster.addApplicationListener(listener);
		}
	}
	if (this.multicaster != null) {
	//监听到其他事件的时候向所有注册在该广播器上的监听器广播事件
		this.multicaster.multicastEvent(event);
	}
}

this.multicaster.multicastEvent(event);后面的逻辑与前面的相同

4、@EventListener

在之前的实例中,我们监听了一个ApplicationEnvironmentPreparedEvent事件,但实际测试却没有监听到,因为@EventListener要在SpringApplication.run的refreshContext中才会被加载,而ApplicationEnvironmentPreparedEvent事件发生在refreshContext之前。
@EventListener 是Spring 提供的注解,在EventListenerMethodProcessor中被加载,并包装成ApplicationListener实例。

Spring Boot 的refreshContext 最终会调用到Spring 的AbstractApplicationContext refresh()

EventListenerMethodProcessor是一个BeanFactoryPostProcessor,会在refresh 的invokeBeanFactoryPostProcessors(beanFactory) 中进行调用

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {

	//使用注册委托类处理BeanFactoryPostProcessor的实现
	PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

	// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
	// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
	if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}
}

getBeanFactoryPostProcessors()会获取已经加载的BeanFactoryPostProcessor实现,比如准备上下文中的PropertySourceOrderingBeanFactoryPostProcessor。
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors内部的方法很长

public static void invokeBeanFactoryPostProcessors(
		ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

	Set<String> processedBeans = new HashSet<>();

//首先处理是BeanDefinitionRegistry的实例
	if (beanFactory instanceof BeanDefinitionRegistry registry) {
		List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
		List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

		for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
			if (postProcessor instanceof BeanDefinitionRegistryPostProcessor registryProcessor) {
				registryProcessor.postProcessBeanDefinitionRegistry(registry);
				registryProcessors.add(registryProcessor);
			}
			else {
				regularPostProcessors.add(postProcessor);
			}
		}

		// 然后其中分别处理实现了 PriorityOrdered、Ordered 和其余的处理器
		List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

		//处理实现了PriorityOrdered的处理器
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
		for (String ppName : postProcessorNames) {
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
				processedBeans.add(ppName);
			}
		}
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		registryProcessors.addAll(currentRegistryProcessors);
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
		currentRegistryProcessors.clear();

		// 处理实现了Ordered的处理器
		postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
		for (String ppName : postProcessorNames) {
			if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
				currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
				processedBeans.add(ppName);
			}
		}
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		registryProcessors.addAll(currentRegistryProcessors);
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
		currentRegistryProcessors.clear();

		// 最后是剩下的处理器
		boolean reiterate = true;
		while (reiterate) {
			reiterate = false;
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
					reiterate = true;
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();
		}

		// 调用迄今为止处理的所有处理器的postProcessBeanFactory回调
		invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
	}

	else {
		// 其他情况调用在上下文实例中注册的工厂处理程序
		invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
	}

	// 处理 BeanFactoryPostProcessor 实现的实例
	String[] postProcessorNames =
			beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

	//在实现PriorityOrdered、Ordered和其他的BeanFactoryPostProcessors之间分离
	List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
	List<String> orderedPostProcessorNames = new ArrayList<>();
	List<String> nonOrderedPostProcessorNames = new ArrayList<>();
	for (String ppName : postProcessorNames) {
		if (processedBeans.contains(ppName)) {
			// 跳过-已在上面的第一阶段中处理
		}
		else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
			priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
		}
		else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
			orderedPostProcessorNames.add(ppName);
		}
		else {
			nonOrderedPostProcessorNames.add(ppName);
		}
	}

	// 首先,调用实现PriorityOrdered的BeanFactoryPostProcessors
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

	
	//调用实现Ordered的BeanFactoryPostProcessors
	List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
	for (String postProcessorName : orderedPostProcessorNames) {
		orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
	}
	sortPostProcessors(orderedPostProcessors, beanFactory);
	invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

	// 最后调用其他的BeanFactoryPostProcessors
	List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
	for (String postProcessorName : nonOrderedPostProcessorNames) {
		nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
	}
	//EventListenerMethodProcessor会在此处被调用
	invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

	//清除缓存的合并bean定义,因为后处理程序可能已经修改了原始元数据,例如替换值中的占位符。。。
	beanFactory.clearMetadataCache();
}
private static void invokeBeanFactoryPostProcessors(
		Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {

	for (BeanFactoryPostProcessor postProcessor : postProcessors) {
	//步骤记录器
		StartupStep postProcessBeanFactory = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process")
				.tag("postProcessor", postProcessor::toString);
				//循环调用postProcessBeanFactory
		postProcessor.postProcessBeanFactory(beanFactory);
		postProcessBeanFactory.end();
	}
}

EventListenerMethodProcessor类中:

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	this.beanFactory = beanFactory;

//获取EventListenerFactory实现类,其用于处理EventListener注解,
//将其封装成ApplicationListener
	Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
	List<EventListenerFactory> factories = new ArrayList<>(beans.values());
	AnnotationAwareOrderComparator.sort(factories);
	this.eventListenerFactories = factories;
}

EventListenerMethodProcessor 实现了SmartInitializingSingleton接口,会在refresh中的finishBeanFactoryInitialization(beanFactory)处调用,finishBeanFactoryInitialization 的作用是实例化所有剩余的非惰性单例。

DefaultListableBeanFactory类中:

//预实例化所有非懒加载的单例 bean,并触发所有适用 bean 的初始化后回调。
public void preInstantiateSingletons() throws BeansException {
	if (logger.isTraceEnabled()) {
		logger.trace("Pre-instantiating singletons in " + this);
	}

	// 访问 beanDefinitionNames,以允许初始化方法注册新的 bean 定义的列表的副本
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

	// 触发所有非延迟加载的单例 bean 的实例化
	for (String beanName : beanNames) {
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
		//如果是工厂 bean,检查是否需要实例化
			if (isFactoryBean(beanName)) {
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
				if (bean instanceof SmartFactoryBean<?> smartFactoryBean && smartFactoryBean.isEagerInit()) {
					getBean(beanName);
				}
			}
			//如果不是工厂bean,则实例化 bean
			else {
				getBean(beanName);
			}
		}
	}

	// 触发所有适用bean的初始化后回调
	for (String beanName : beanNames) {
		Object singletonInstance = getSingleton(beanName);
		if (singletonInstance instanceof SmartInitializingSingleton smartSingleton) {
		// 启动一个 smart-initialize 的 StartupStep 作为性能分析;
       // 在执行完 smartSingleton.afterSingletonsInstantiated() 之后结束这个 StartupStep。
			StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
					.tag("beanName", beanName);
			smartSingleton.afterSingletonsInstantiated();
			smartInitialize.end();
		}
	}
}

通过smartSingleton.afterSingletonsInstantiated()又执行到了EventListenerMethodProcessorafterSingletonsInstantiated,后面又是一长串,我们直接看最后的重点吧。
在这里插入图片描述
首先根据@EventListener创建成ApplicationListener,然后通过addApplicationListener将监听器存入上下文中,后面的逻辑跟前面是相同的。

内置的监听器

Spring Boot 内置了不少监听器,每个监听器都有自己的作用
在这里插入图片描述

  • ClearCachesApplicationListener
    应用上下文加载完成后对缓存做清除工作
  • ParentContextCloserApplicationListener
    父应用程序上下文关闭时,会将关闭事件向下传播以关闭该应用程序上下文
  • FileEncodingApplicationListener
    用于监听应用程序环境准备完毕时,如果系统文件编码(spring.mandatory-file-encoding)与环境中配置的值(file.encoding)不匹配时(忽略大小写),会抛出异常,并停止应用程序
  • AnsiOutputApplicationListener
    根据spring.output.ansi.enabled参数配置AnsiOutput
  • DelegatingApplicationListener
    用于委托管理context.listener.classes中配置的监听器
  • LoggingApplicationListener
    配置和初始化Spring Boot 的日志系统
  • EnvironmentPostProcessorApplicationListener
    管理spring.factories文件中注册的EnvironmentPostProcessors

内置的事件

Spring Boot 包中部分事件:
BootstrapContextClosedEvent、ExitCodeEvent、AvailabilityChangeEvent、ParentContextAvailableEvent、ApplicationContextInitializedEventApplicationEnvironmentPreparedEventApplicationFailedEventApplicationPreparedEventApplicationReadyEventApplicationStartedEventApplicationStartingEventWebServerInitializedEvent、ReactiveWebServerInitializedEvent、ServletWebServerInitializedEvent

Spring 包中部分事件:
ContextClosedEvent、ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、ServletRequestHandledEvent

总结

最后还是用一张图来总结整个流程

在这里插入图片描述


作者其他文章:
Prometheus 系列文章

  1. Prometheus 的介绍和安装
  2. 直观感受PromQL及其数据类型
  3. PromQL之选择器和运算符
  4. PromQL之函数
  5. Prometheus 告警机制介绍及命令解读
  6. Prometheus 告警模块配置深度解析
  7. Prometheus 配置身份认证
  8. Prometheus 动态拉取监控服务
  9. Prometheus 监控云Mysql和自建Mysql

Grafana 系列文章,版本:OOS v9.3.1

  1. Grafana 的介绍和安装
  2. Grafana监控大屏配置参数介绍(一)
  3. Grafana监控大屏配置参数介绍(二)
  4. Grafana监控大屏可视化图表
  5. Grafana 查询数据和转换数据
  6. Grafana 告警模块介绍
  7. Grafana 告警接入飞书通知

Spring Boot Admin 系列

  1. Spring Boot Admin 参考指南
  2. SpringBoot Admin服务离线、不显示健康信息的问题
  3. Spring Boot Admin2 @EnableAdminServer的加载
  4. Spring Boot Admin2 AdminServerAutoConfiguration详解
  5. Spring Boot Admin2 实例状态监控详解
  6. Spring Boot Admin2 自定义JVM监控通知
  7. Spring Boot Admin2 自定义异常监控
  8. Spring Boot Admin 监控指标接入Grafana可视化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/621601.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于三种机器学习模型的岩爆类型预测及Python实现

写在前面 由于代码较多&#xff0c;本文仅展示部分关键代码&#xff0c;需要代码文件和数据可以留言 然而&#xff0c;由于当时注释不及时&#xff0c;且时间久远&#xff0c;有些细节笔者也记不清了&#xff0c;代码仅供参考 0 引言 岩爆是深部岩土工程施工过程中常见的一种地…

GitHub创建新的项目

想把最近自己做的一些东西整理一下上传到网上进行保存&#xff0c;然后就想到了Github&#xff0c;结果发现自己不会上传&#xff0c;所以去BiliBili大学学习了一下&#xff0c;一下内容主要参考《【程序员一定要掌握的技巧】使用Git上传本地代码到GitHub教程》。 使用Git上传本…

Win10每次开机鼠标桌面右键都会显示撤销删除解决方法

Win10每次开机鼠标桌面右键都会显示撤销删除解决方法分享。有用户电脑开机的时候&#xff0c;就会自动弹出撤销删除的窗口了。那么这个问题是怎么回事呢&#xff1f;接下来我们就一起来看看以下的详细操作方法教学吧。 情况一&#xff1a; 如果是联想&#xff0c;在联想管家把联…

Android 中的 NDK 到底是什么?(详细解析+案例实战)

NDK 提供了一系列的工具&#xff0c;帮助开发者快速开发 C (或 C )的动态库&#xff0c;并能自动将 so 和 java 应用一起打包成 apk&#xff1b;这些工具对开发者的帮助是巨大的 什么是 NDK &#xff1f; Android 原生开发包 NDK(Native Delopment kits )将用于 Android 平台上…

Vue中process.env关键字,process.env.VUE_APP_BASE_API

1.process.env 是Node.js 中的一个环境 打开命令行查看环境&#xff1a; 2.process.env与Vue CLI 项目 Vue Cli 有以下三种运行模式 development 模式用于 vue-cli-service serve test 模式用于 vue-cli-service test:unit production 模式用于 vue-cli-service build 和 vue-c…

pip安装教程 python(针对于Windows系统)

1.什么是pip pip 是 Python 包管理工具&#xff0c;该工具提供了对Python 包的查找、下载、安装、卸载的功能。 目前如果你在 python.org 下载最新版本的安装包&#xff0c;则是已经自带了该工具。 pip 官网&#xff1a;https://pypi.org/project/pip/ 2.判断本机是否安装p…

chatgpt赋能python:Python中如何将NaN变为0

Python中如何将NaN变为0 Python是一种动态、强类型的编程语言&#xff0c;因其简单易学、功能强大&#xff0c;被广泛应用于各种领域。其中NumPy和Pandas是数据科学界最常用的Python库&#xff0c;而在数据处理中&#xff0c;处理缺失值通常是必不可少的。本文将介绍如何使用P…

学成在线----day3

1、JSR303校验 对填入的数据自动做一些约束 package com.xuecheng.content.model.dto;import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data;import javax.validation.constraints.NotEmpty; import javax.validati…

PyCharm安装教程(2023年,3月)

下载PyCharm之前需要准备下载Python 链接&#xff1a;Python安装教程 一、PyCharm下载 1、进入JetBrains官网&#xff1a; 官网地址&#xff1a;https://www.jetbrains.com/ 2、点击【Developer Tools】 开发者工具&#xff0c;选择【PyCharm】点击跳转到PyCharm界面。点击…

【Docker】 7.Docker Internet

文章目录 Docker InternetDocker Internet CommandDocker Bridge Internetdocker Host InternetDocker Container InternetDocker None Internet Docker Internet Docker 网络架构采用的设计规范是CNM&#xff08;Container Network Model&#xff09;。CNM中规定了Docker网络…

RK3588平台开发系列讲解(同步与互斥篇)自旋锁死锁实验

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、自旋锁死锁二、实验程序的编写2.1、驱动程序编写2.2、编写测试 APP沉淀、分享、成长,让自己和他人都能有所收获!😄 📢自旋锁若是使用不当就会产生死锁,在本篇将会对自旋锁的特殊情况-死锁进行讲解。 一、自…

0801详解-redux-react

文章目录 1 redux1.1 概述1.2 示例实现页面数字的加、减1.3 异步加-异步action 2 react-redux2.1 概述2.2 优化示例代码 3 数据共享4 redux开发者工具5 小结5.1 求和案例_redux精简版5.2 求和案例_redux完整版5.3 求和案例_redux异步action版5.4 求和案例_react-redux基本使用5…

【哈士奇赠书活动 - 25期】-〖Python自动化办公应用大全(ChatGPT版) 〗

文章目录 ⭐️ 赠书 - 《Python自动化办公应用大全&#xff08;ChatGPT版&#xff09;》⭐️ 内容简介⭐️ 作者简介⭐️ 编辑推荐⭐️ 赠书活动 → 获奖名单 ⭐️ 赠书 - 《Python自动化办公应用大全&#xff08;ChatGPT版&#xff09;》 ⭐️ 内容简介 本书全面系统地介绍了P…

使用YOLOv5实现图片、视频的目标检测

推断的准备工作 接下来我将从官方代码开始&#xff0c;一步一步展示如何进行图片、视频识别 首先从GitHub下载官方代码&#xff08;也可以从下面链接获取&#xff09;&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/16wzV899D90TY2Xwhx4TwhA 提取码&#xff1a;vzvj …

MYSQL必知必会,详尽入门,一文帮你学会SQL必知必会

目录 前言 数据库的概念和术语 SQL语言和组成 DDL show : 展示当前已有的数据库或者表 create &#xff1a;创建一个数据库或者一个表 drop &#xff1a;删除表、数据库对象或者视图 alter &#xff1a;修改现有的数据库对象&#xff0c;例如 修改表的属性或者字段 (…

geth下载安装配置环境及联盟链的搭建

以太坊概论考察课 更具课堂教学讲解&#xff0c;参考开放资料。使用所学的知识&#xff0c;创建项目并完成要求的内容。包含的功能和要求具体如下&#xff1a; 一&#xff1a;安装并运行geth客户端 1、下载安装geth 首先下载geth&#xff1a;https://geth.ethereum.org/dow…

javaScript蓝桥杯---视频弹幕

目录 一、介绍二、准备三、⽬标四、代码五、完成 一、介绍 弹幕指直接显现在视频上的评论&#xff0c;可以以滚动、停留甚⾄更多动作特效⽅式出现在视频上&#xff0c;是观看视频的⼈发送的简短评论。通过发送弹幕可以给观众⼀种“实时互动”的错觉&#xff0c;弹幕的出现让观…

Segment Anything Model (SAM)——卷起来了,那个号称分割一切的CV大模型他来了

最近每天打开微信看到10个公众号里面差不多有11个都在各种玩赚chatGPT&#xff0c;每个都在说是各种大好风口&#xff0c;哎&#xff0c;看得眼睛都是累的。 今天下午无意间看到Meta发布了一款号称能分割一切的CV大模型&#xff0c;CV圈也开始卷起来&#xff0c;今年各种大模型…

chatgpt赋能python:Python在图片处理方面的应用

Python在图片处理方面的应用 在当今数字化的时代&#xff0c;图像处理已成为不可避免的技术。越来越多的业务需要对图片进行处理、识别和分析。Python是一种易于使用且适合处理图像的编程语言。Python中有许多图像处理库&#xff0c;例如Pillow、Scikit-Image和OpenCV等&#…

基于BP神经网络的PID智能控制

基于BP神经网络的PID智能控制 基于BP神经网络的PID整定原理经典的增量式数字PID控制算法为&#xff1a;BP神经网络结构&#xff1a;学习算法仿真模型Matlab代码仿真效果图结论python仿真参考文献 基于BP神经网络的PID整定原理 PID控制要获得较好的控制效果&#xff0c;就必须通…