springboot源码分析之事件发布机制浅析
springboot 事件发布机制浅析
文章目录
- springboot源码分析之事件发布机制浅析
- 前言
- 一、自定义事件发布
- 1.定义事件
- 2.监听事件
- 3.发布事件
- 二、源码分析
- Listener监听器注册
- 事件发布与执行
- 总结
前言
事件发布机制在Spring Boot框架中扮演着重要的角色,它是实现模块解耦、扩展和定制以及自动化配置的关键机制之一。通过事件发布机制,开发者可以实现高度可扩展和可定制的应用程序,并更好地利用Spring Boot框架的各种特性和功能。文章主要包含两个部分,一个是如何使用springboot的事件发布,另一个就是分析其运行原理。
事件发布机制也是使用了
观察者模式
来实现的,如果你没了解过观察者模式建议先了解一下观察者模式
一、自定义事件发布
1.定义事件
自定义实现类,实现ApplicationEvent类
public class UserUpdateEvent extends ApplicationEvent {public UserUpdateEvent(User updateUser) {super(updateUser);}/*** 获取事件属性* @return*/public User getUser() {return (User)this.source;}
}
2.监听事件
监听事件、执行处理逻辑
方式1:实现ApplicationListener类,需要自己将listener注册到应用中
public class UserUpdateCacheListener implements ApplicationListener<UserUpdateEvent> {@Overridepublic void onApplicationEvent(UserUpdateEvent userUpdateEvent) {User user = userUpdateEvent.getUser();System.out.println(JSON.toJSONString(user));System.out.println("获取到最新用户信息 ----更新缓存");}
}
启动类中注册
public static void main(String[] args) throws InterruptedException {TypeUtils.compatibleWithJavaBean = true;SpringApplication app =new SpringApplication(DemoApplication.class);app.addListeners(new SpringBootEvnetListenner());//加入自定义的监听类app.addListeners(new UserUpdateCacheListener());//加入自定义的监听类app.addListeners(new UserUpdateDBListener());//加入自定义的监听类app.run(args);}
利用SPI机制注册,在resource下面新建META-INF/spring.factories
org.springframework.context.ApplicationListener=\
com.tfzg.program.core.UserUpdateCacheListener
方式2:直接使用@EventListener标记方法,参数为监听的事件
@Configuration
public class EventListenerConfig {@EventListenerpublic void userListener(UserUpdateEvent event){System.out.println("-------------22----------");System.out.println(event.getUser().getName());}
}
3.发布事件
@AutowiredApplicationContext applicationContext;@RequestMapping("/pushEvent")public String testPushEvent(){User user = new User();applicationContext.publishEvent(new UserUpdateEvent(user));return "s";}
二、源码分析
主要从两个方面分析springboot的事件发布机制吧,从监听器注册和事件发布执行这两个方向分析springboot事件发布机制原理。
Listener监听器注册
从springboot启动流程,以及bean的生命周期入手,进行分析Listener注册原理
1.1 SpringApplication 构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));this.webApplicationType = WebApplicationType.deduceFromClasspath();this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));//注册Listener的关键入口就在这儿、通过getSpringFactoriesInstances获取到Listener集合,然后set到SpringApplication 的Listeners 属性中setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = deduceMainApplicationClass();}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = getClassLoader();// Use names and ensure unique to protect against duplicatesSet<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances;}
通过上面的setListeners方法和getSpringFactoriesInstances
,可以知道springboot启动的时候,是通过SPI
的机制加载spring.factories
文件中配置ApplicationListener,去读取到Listener的,因此我们也可以在spring.factories 中添加自定义Listener或者在SpringApplication 类初始化后直接调用addListeners方法进行添加。
1.2 processBean
阶段会处理有@EventListener
注解的方法,对方法解析生成一个ApplicationListenerMethodAdapter Listener
private void processBean(final String beanName, final Class<?> targetType) {if (!this.nonAnnotatedClasses.contains(targetType) &&AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&!isSpringContainerClass(targetType)) {Map<Method, EventListener> annotatedMethods = null;try {annotatedMethods = MethodIntrospector.selectMethods(targetType,(MethodIntrospector.MetadataLookup<EventListener>) method ->AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));}catch (Throwable ex) {// An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.if (logger.isDebugEnabled()) {logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);}}if (CollectionUtils.isEmpty(annotatedMethods)) {this.nonAnnotatedClasses.add(targetType);if (logger.isTraceEnabled()) {logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());}}else {// Non-empty set of methodsConfigurableApplicationContext context = this.applicationContext;Assert.state(context != null, "No ApplicationContext set");List<EventListenerFactory> factories = this.eventListenerFactories;Assert.state(factories != null, "EventListenerFactory List not initialized");for (Method method : annotatedMethods.keySet()) {for (EventListenerFactory factory : factories) {if (factory.supportsMethod(method)) {Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));// 关键代码,包装成了ListenerApplicationListener<?> applicationListener =factory.createApplicationListener(beanName, targetType, methodToUse);if (applicationListener instanceof ApplicationListenerMethodAdapter) {((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);}// 将Listener 加入Listener中context.addApplicationListener(applicationListener);break;}}}if (logger.isDebugEnabled()) {logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +beanName + "': " + annotatedMethods);}}}}
事件发布与执行
通过applicationContext.publishEvent方法入手,进入关键代码AbstractApplicationEventMulticaster.multicastEvent
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));Executor executor = getTaskExecutor();//过滤Listener,遍历执行监听器方法for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {if (executor != null) {executor.execute(() -> invokeListener(listener, event));}else {//执行 Listener onApplicationEvent 方法invokeListener(listener, event);}}}
根据事件类型,将指定Listener从所有Listener中获取出来,然后再遍历过滤出来的Listener,再遍历执行onApplicationEvent方法。
总结
本篇文章主要展示了springboot事件发布机制的使用,以及运行原理的关键代码。
(如果大家觉得有帮助,帮忙点点赞啦!!!!!!!!!!!!!!!!!!!)