Spring异步事件机制剖析

简介: Spring异步事件机制剖析

同步&异步


  • 同步事件
    在一个线程里,所有的业务方法都是顺序执行的,存在上下依赖关系,其中一个环节耗时过长或阻塞会影响后续环节,且整体耗时增加也受到影响。
    网络异常,图片无法展示
    |
  • 异步事件
    在一个线程里,执行一个业务方法或逻辑,其他业务方法或逻辑通过异步线程进行并行执行,彼此独立不影响,可以充分利用多线程的优势提高并发,减少整体耗时。
    网络异常,图片无法展示
    |


实现原理


交互流程


网络异常,图片无法展示
|


  • publisher 事件发布器,这里是事件对象的发布入口
  • listener 事件监听器,这里是事件对象处理的最终对象
  • event 事件对象,事件数据的载体
  • applicationEventMultiCaster 事件多播器,它是连接发布器与监听器的桥梁和中转路由,负责将事件对象分发到具体的监听器上去


Spring中的事件机制是通过观察者模式来进行实现的,支持同步/异步两种方式。


Spring的事件机制提供了一种可以实现业务解耦的优雅编程方式,将实现剥离,使得实现细节更加具体和聚焦,在一定程度上便于后续维护,扩展性较好。


一般来说,我们使用异步方式进行,否则便和日常的同步调用没有太大区别,无法充分发挥异步线程带来的并行优势。

特点

作用

观察者模式

解耦

异步

并行化


初始化


关于Spring事件机制的初始化,其实主要是基于观察者模式进行发布器、监听器路由关系的绑定和建立,事件多播器也是依赖映射关系进行事件对象的分发实现具体监听器的处理。


Spring事件机制只是整个Spring环境中的一个组成部分,这里需要前置了解Spring环境的初始化方式和工作原理后再结合剖析事件机制的初始化就不难理解了。我们知道AbstractApplicationContext是Spring中环境的抽象基类,它的refresh()方法涵盖了所有整个Spring初始化流程,这里面就包含多播器的初始化方法initApplicationEventMulticaster()和监听器的绑定方法registerListeners()


public void refresh() throws BeansException, IllegalStateException {

       //。。。

    //省略其他

       synchronized(this.startupShutdownMonitor) {

           //。。。

           //省略其他

           try {

               //。。。

               //省略其他

               this.initApplicationEventMulticaster();

               this.registerListeners();

               //省略其他

               //。。。

           } catch (BeansException var9) {

               //。。。

               //省略其他

           } finally {

               //。。。

               //省略其他

           }

       }

   }


下面来看下多播器的初始化方法initApplicationEventMulticaster(),主要是从BeanFactory中判断是否已创建多播器,如果没有创建则创建默认的SimpleApplicationEventMulticaster作为多播器。


protected void initApplicationEventMulticaster() {

// 拿到当前BeanFactory,通过Bean工厂来获取多播器的Bean实例

       ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();

       // 如果存在多播器,则直接获取

       if (beanFactory.containsLocalBean("applicationEventMulticaster")) {

           this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);

           if (this.logger.isDebugEnabled()) {

               this.logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");

           }

       }

// 如果不存在多播器,则直接创建默认的SimpleApplicationEventMulticaster多播器进行Bean注册

else {

           this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);

           beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster);

           if (this.logger.isDebugEnabled()) {

               this.logger.debug("Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [" + this.applicationEventMulticaster + "]");

           }

       }

   }


监听器的注册方法registerListeners()


protected void registerListeners() {

// 获取所有ApplicationListener的迭代器

       Iterator var1 = this.getApplicationListeners().iterator();

// 把所有监听器都注册到当前的多播器上去

       while(var1.hasNext()) {

           ApplicationListener<?> listener = (ApplicationListener)var1.next();

           this.getApplicationEventMulticaster().addApplicationListener(listener);

       }


       String[] listenerBeanNames = this.getBeanNamesForType(ApplicationListener.class, true, false);

       String[] var7 = listenerBeanNames;

       int var3 = listenerBeanNames.length;


       for(int var4 = 0; var4 < var3; ++var4) {

           String listenerBeanName = var7[var4];

           this.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);

       }

// 如果是早期事件,则直接遍历执行发布事件对象

       Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;

       this.earlyApplicationEvents = null;

       if (earlyEventsToProcess != null) {

           Iterator var9 = earlyEventsToProcess.iterator();


           while(var9.hasNext()) {

               ApplicationEvent earlyEvent = (ApplicationEvent)var9.next();

               this.getApplicationEventMulticaster().multicastEvent(earlyEvent);

           }

       }

   }


发布事件


发布事件是通过AbstractApplicationContextpublishEvent()方法发布的


public void publishEvent(Object event) {

publishEvent(event, null);

}


protected void publishEvent(Object event, @Nullable ResolvableType eventType) {

Assert.notNull(event, "Event must not be null");


// 判断事件类型是否为ApplicationEvent,如果不是则封装成PayloadApplicationEvent

ApplicationEvent applicationEvent;

if (event instanceof ApplicationEvent) {

applicationEvent = (ApplicationEvent) event;

}

else {

applicationEvent = new PayloadApplicationEvent<>(this, event);

if (eventType == null) {

  eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();

}

}


// 如果是Spring初始化的早期事件,则需要加入到早期事件中立即发布

if (this.earlyApplicationEvents != null) {

this.earlyApplicationEvents.add(applicationEvent);

}

else {

//如果不是早期事件,则通过多播器立即进行事件发布

getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);

}

 

//如果父类上下文存在,进行发布事件

if (this.parent != null) {

if (this.parent instanceof AbstractApplicationContext) {

  ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);

}

else {

  this.parent.publishEvent(event);

}

}

}


然后再来看下SimpleApplicationEventMulticastermulticastEvent()方法,这是多播器广播事件的方法


public void multicastEvent(ApplicationEvent event) {

//解析Event类型,进行事件发布

multicastEvent(event, resolveDefaultEventType(event));

}


public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {

// 获取到事件对应的解析类型

ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));

// 获取到多播器当前的线程池

Executor executor = getTaskExecutor();

// 获取当前应用中与给定事件类型匹配的ApplicationListeners的监听器集合,不符合的监听器会被排除在外。再循环执行

for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {

// 如果线程池不为空,则通过线程池异步执行

if (executor != null) {

  executor.execute(() -> invokeListener(listener, event));

}

else {

  // 否则由当前线程执行

  invokeListener(listener, event);

}

}

}


事件处理


事件处理由invokeListener()方法进行处理,该方法做了一层try、catch封装,实际方法在doInvokeListener()方法中的listener.onApplicationEvent(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 {

// 实际监听器接受该事件并处理

listener.onApplicationEvent(event);

}

catch (ClassCastException ex) {

String msg = ex.getMessage();

if (msg == null || matchesClassCastMessage(msg, event.getClass())) {

  Log logger = LogFactory.getLog(getClass());

  if (logger.isTraceEnabled()) {

  logger.trace("Non-matching event type for listener: " + listener, ex);

  }

}

else {

  throw ex;

}

}

}


关系匹配


当发布器发布事件对象后,会通过getApplicationListeners方法进行监听器的获取,返回的监听器集合进行遍历和类型解析,匹配到符合条件的监听器。


protected Collection<ApplicationListener<?>> getApplicationListeners(

ApplicationEvent event, ResolvableType eventType) {

// 最初发送事件的对象

Object source = event.getSource();

Class<?> sourceType = (source != null ? source.getClass() : null);

// 将给定事件类型与源类型进行封装

ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

// Quick check for existing entry on ConcurrentHashMap...

ListenerRetriever retriever = this.retrieverCache.get(cacheKey);

if (retriever != null) {

return retriever.getApplicationListeners();

}


if (this.beanClassLoader == null ||

  (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&

    (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {

// 完全同步构建和缓存ListenerRetriever

synchronized (this.retrievalMutex) {

  retriever = this.retrieverCache.get(cacheKey);

  if (retriever != null) {

  return retriever.getApplicationListeners();

  }

  retriever = new ListenerRetriever(true);

  //实际检索给定事件和源类型的应用程序监听器,将过滤后的监听器集合进行返回

  Collection<ApplicationListener<?>> listeners =

    retrieveApplicationListeners(eventType, sourceType, retriever);

  this.retrieverCache.put(cacheKey, retriever);

  return listeners;

}

}

else {

// No ListenerRetriever caching -> no synchronization necessary

return retrieveApplicationListeners(eventType, sourceType, null);

}

}


通过retrieveApplicationListeners()方法,进行实际检索给定事件和源类型的应用程序监听器的实现。通过supportsEvent()方法进行判断监听器是否支持给定事件。


private Collection<ApplicationListener<?>> retrieveApplicationListeners(

ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {


List<ApplicationListener<?>> allListeners = new ArrayList<>();

//当前应用中的监听器集合

Set<ApplicationListener<?>> listeners;

//当前应用中的监听器BeanName集合

Set<String> listenerBeans;

synchronized (this.retrievalMutex) {

listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);

listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);

}

for (ApplicationListener<?> listener : listeners) {

// 判断监听器是否支持给定事件

if (supportsEvent(listener, eventType, sourceType)) {

  if (retriever != null) {

  retriever.applicationListeners.add(listener);

  }

  allListeners.add(listener);

}

}

if (!listenerBeans.isEmpty()) {

BeanFactory beanFactory = getBeanFactory();

for (String listenerBeanName : listenerBeans) {

  try {

  //根据监听器的BeanName获取到对应类型

  Class<?> listenerType = beanFactory.getType(listenerBeanName);

  if (listenerType == null || supportsEvent(listenerType, eventType)) {

    ApplicationListener<?> listener =

      beanFactory.getBean(listenerBeanName, ApplicationListener.class);

    //判断监听器是否支持给定事件

    if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {

    if (retriever != null) {

      if (beanFactory.isSingleton(listenerBeanName)) {

      retriever.applicationListeners.add(listener);

      }

      else {

      retriever.applicationListenerBeans.add(listenerBeanName);

      }

    }

    allListeners.add(listener);

    }

  }

  }

  catch (NoSuchBeanDefinitionException ex) {

  // Singleton listener instance (without backing bean definition) disappeared -

  // probably in the middle of the destruction phase

  }

}

}

AnnotationAwareOrderComparator.sort(allListeners);

if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {

retriever.applicationListeners.clear();

retriever.applicationListeners.addAll(allListeners);

}

return allListeners;

}


配置方式


开启异步


  • 注解方式


/**

* created by guanjian on 2021/4/7 9:36

*/

@Configuration

@EnableAsync

public class AsyncConfig{

// 这里还可以配置其他更多可选项,如异步线程池等

}


  • XML方式


<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"

      xmlns:aop="http://www.springframework.org/schema/aop"

      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/taskhttp://www.springframework.org/schema/task/spring-task.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd">


   <!--开启注解调度支持 等同于@Async注解 这里executor是指定线程池,有下面两种异步线程池的配置方式 -->

   <task:annotation-driven />


</beans>


<task:annotation-driven "/>是开启异步,等同于@Async注解的作用。


多播器定义


<bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">

       <property name="taskExecutor" ref="executor" />

</bean>


如果这里不定义也可以,会在初始化阶段创建SimpleApplicationEventMulticaster来作为默认的多播器。


异步线程定义


  • 注解方式


/**

* created by guanjian on 2021/4/7 9:36

*/

@Configuration

@EnableAsync

public class AsyncConfig implements AsyncConfigurer {

   /**

    * 这里手动注入异步线程池

    */

   @Override

   public Executor getAsyncExecutor() {

       ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

       //核心线程池数量

       executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());

       //最大线程数量

       executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 5);

       //线程池的队列容量

       executor.setQueueCapacity(Runtime.getRuntime().availableProcessors() * 2);

       //线程名称的前缀

       executor.setThreadNamePrefix("async-executor-");

       executor.initialize();

       return executor;

   }


   /**

    * 这里注入异步未知错误捕获处理

    */

   @Override

   public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {

       return new SimpleAsyncUncaughtExceptionHandler();

   }

}


实现AsyncConfigurer接口完成异步调用的相关配置,getAsyncExecutor是配置异步线程池,getAsyncUncaughtExceptionHandler是配置异步未知错误捕获处理。


  • XML方式


<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"

      xmlns:aop="http://www.springframework.org/schema/aop"

      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/taskhttp://www.springframework.org/schema/task/spring-task.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd">


   <!-- 开启@AspectJ AOP代理 -->

   <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>

   <!--开启注解调度支持 等同于@Async注解 这里executor是指定线程池,有下面两种异步线程池的配置方式 -->

   <task:annotation-driven executor="executor" proxy-target-class="true"/>


   <!-- 配置方式1:异步线程池 -->

   <task:executor id="executor" pool-size="10" keep-alive="3000" queue-capacity="200" rejection-policy="CALLER_RUNS"/>

   <!-- 配置方式2:异步线程池 -->

   <bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">

       <property name="corePoolSize" value="5"/>

       <property name="keepAliveSeconds" value="3000"/>

       <property name="maxPoolSize" value="50"/>

       <property name="queueCapacity" value="200"/>

   </bean>

</beans>


<task:annotation-driven executor=“executor” proxy-target-class=“true”/>是开启异步,等同于@Async注解的作用,executor属性用来指定异步线程池,上面的示例中配置了两种异步线程池,指定哪一个都可以。
使用<task:executor />这种,配置风格一致更清晰,它是线程池在异步事件机制中的特殊schema支持,参数有限。
使用标准的Bean对org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor进行配置的话,可以支持最全面属性配置。


关于异步线程池的配置,可以通过代码分析看细节,这里先说结论。


  • 在开启了异步的情况下,没有配置、且没有指定任何线程池则自动调用内部实现SimpleAsyncTaskExecutor线程池进行异步执行
  • 如果配置了org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor线程池,即时没指定也会默认以此线程池进行异步执行
  • 如果指定了异步线程池,则按照指定的异步线程池进行异步执行,与其他线程池隔离,互不干扰


事件定义


/**

* created by guanjian on 2021/4/6 17:46

*/

public class EventObject extends ApplicationEvent {


   public EventObject(Object source) {

       super(source);

   }

}


继承ApplicationEvent类进行事件对象的扩展,该对象用来事件对象数据的传递,由publisher发布对象事件,由指定的listener来进行监听接收。


事件发布


/**

* created by guanjian on 2021/4/6 17:40

*/

@Component

public class AsyncPublisher implements ApplicationEventPublisherAware {


   private final static Logger LOGGER = LoggerFactory.getLogger(AsyncPublisher.class);


   @Resource

   private ApplicationEventPublisher publisher;


   @Override

   public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {

       this.publisher = applicationEventPublisher;

   }


   public void publish(EventObject eventObject) {

       LOGGER.info("Thread={} 发布事件 source={}",Thread.currentThread().getName(), eventObject.getSource());

       this.publisher.publishEvent(eventObject);

   }

}


实现ApplicationEventPublisherAware接口的方法,将ApplicationEventPublisher注入并通过它来调用publishEvent()方法进行事件发布。


事件监听


/**

* created by guanjian on 2021/4/6 17:42

*/

@Component

public class AsyncListener implements ApplicationListener<EventObject> {


   private final static Logger LOGGER = LoggerFactory.getLogger(AsyncListener.class);


   @Async

   @Override

   public void onApplicationEvent(EventObject eventObject) {

       LOGGER.info("Thread={} 监听事件 source={}", Thread.currentThread().getName(), eventObject.getSource());

   }

}


@Async注解是开启方法异步执行,不开启则是同步执行


注意: 无论是publisher还是listener都要纳入spring的管理才可以生效


失效原因


  • 没有通过@EnableAsync注解开启异步支持,或没有通过xml配置<task:annotation-driven />开启异步支持
  • 监听方法没有加@Async注解
  • 发布器(publisher)、监听器(listener)都要参与到Spring的管理中来,检查是否忘记@Component注解标记


实战举例


基于MQ消息实现的,基于用户信息变化事件的异步分发


关系拓扑


网络异常,图片无法展示
|


目录结构


│ MqEvent.java // 事件发布对象
│ MqEventEnums.java // 事件枚举
│ MqEventListener.java // 事件监听器
│ MqEventPublisher.java // 事件发布器

├─handler
│ UserInfoInvalidEventHandler.java // 失效事件处理器
│ UserInfoModifyEventHandler.java // 修改事件处理器
│ UserInfoValidEventHandler.java // 生效事件处理器

├─holder
│ MqEventHolder.java // 事件枚举与事件处理器关系容器

└─vo
UserInfoInValidEventVo.java // 失效事件对象
UserInfoModifyEventVo.java // 修改事件对象
UserInfoValidEventVo.java // 生效事件对象


优点&缺点


优点


  • 业务解耦
  • 异步化处理,减少同步执行阻塞


缺点


  • 知识盲区多,需要深刻理解实现机制和原理,结合Spring配置进行使用,如果忽略底层实现不但起不到作用,反而适得其反
  • 由于是异步线程并行处理,不适合前后依赖的业务逻辑,也不适合做事务特性操作的逻辑处理


扩展


CompletableFuture


参考


Spring的事件机制详解
Spring之事件机制详解
Spring异步编程 | 你的@Async就真的异步吗?异步历险奇遇记


相关文章
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
76 2
|
9天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
53 14
|
20天前
|
缓存 Java 数据库连接
Spring框架中的事件机制:深入理解与实践
Spring框架是一个广泛使用的Java企业级应用框架,提供了依赖注入、面向切面编程(AOP)、事务管理、Web应用程序开发等一系列功能。在Spring框架中,事件机制是一种重要的通信方式,它允许不同组件之间进行松耦合的通信,提高了应用程序的可维护性和可扩展性。本文将深入探讨Spring框架中的事件机制,包括不同类型的事件、底层原理、应用实践以及优缺点。
49 8
|
26天前
|
缓存 Java 数据库连接
深入探讨:Spring与MyBatis中的连接池与缓存机制
Spring 与 MyBatis 提供了强大的连接池和缓存机制,通过合理配置和使用这些机制,可以显著提升应用的性能和可扩展性。连接池通过复用数据库连接减少了连接创建和销毁的开销,而 MyBatis 的一级缓存和二级缓存则通过缓存查询结果减少了数据库访问次数。在实际应用中,结合具体的业务需求和系统架构,优化连接池和缓存的配置,是提升系统性能的重要手段。
41 4
|
1月前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
62 8
|
3月前
|
Java Spring 容器
Spring使用异步注解@Async正确姿势
Spring使用异步注解@Async正确姿势,异步任务,spring boot
|
2月前
|
自然语言处理 JavaScript Java
Spring 实现 3 种异步流式接口,干掉接口超时烦恼
本文介绍了处理耗时接口的几种异步流式技术,包括 `ResponseBodyEmitter`、`SseEmitter` 和 `StreamingResponseBody`。这些工具可在执行耗时操作时不断向客户端响应处理结果,提升用户体验和系统性能。`ResponseBodyEmitter` 适用于动态生成内容场景,如文件上传进度;`SseEmitter` 用于实时消息推送,如状态更新;`StreamingResponseBody` 则适合大数据量传输,避免内存溢出。文中提供了具体示例和 GitHub 地址,帮助读者更好地理解和应用这些技术。
431 0
|
4月前
|
Java 开发工具 Spring
Spring的Factories机制介绍
Spring的Factories机制介绍
98 1
|
4月前
|
Java Spring 供应链
Spring 框架事件发布与监听机制,如魔法风暴席卷软件世界,开启奇幻编程之旅!
【8月更文挑战第31天】《Spring框架中的事件发布与监听机制》介绍了Spring中如何利用事件发布与监听机制实现组件间的高效协作。这一机制像城市中的广播系统,事件发布者发送消息,监听器接收并响应。通过简单的示例代码,文章详细讲解了如何定义事件类、创建事件发布者与监听器,并确保组件间松散耦合,提升系统的可维护性和扩展性。掌握这一机制,如同拥有一把开启高效软件开发大门的钥匙。
54 0
|
4月前
|
监控 Java API
Spring Boot中的异步革命:构建高性能的现代Web应用
【8月更文挑战第29天】Spring Boot 是一个简化 Spring 应用开发与部署的框架。异步任务处理通过后台线程执行耗时操作,提升用户体验和系统并发能力。要在 Spring Boot 中启用异步任务,需在配置类上添加 `@EnableAsync` 注解,并定义一个自定义的 `ThreadPoolTaskExecutor` 或使用默认线程池。通过 `@Async` 注解的方法将在异步线程中执行。异步任务适用于发送电子邮件、数据处理、外部 API 调用和定时任务等场景。最佳实践中应注意正确配置线程池、处理返回值和异常、以及监控任务状态,确保系统的稳定性和健壮性。
45 0