美文网首页
Spring事件监听

Spring事件监听

作者: 书上得来终觉浅 | 来源:发表于2020-07-08 16:33 被阅读0次

Spring提供了事件监听,流程如下:

image-20200708144655101

定义事件

本列中定义了日志记录事件ApiEvent,是ApplicationEvent的子类。

//定义日志记录事件
public class ApiEvent extends ApplicationEvent {
    private String content;

    public ApiEvent(Object source, String content) {
        super(source);
        this.content = content;
    }

    public String getContent() {
        return content;
    }
}

注册事件监听器

定义ApiEventListener监听器,需要继承ApplicationListener接口,并实现onApplicationEvent方法,通过@Component注入到Context中。

@Component
public class ApiEventListener implements ApplicationListener<LogEvent> {

    private static final Logger logger = LoggerFactory.getLogger(ApiEventListener.class);

    @Override
    public void onApplicationEvent(ApiEvent event) {
        logger.info("收到Api调用事件,内容 {} ",event.getContent());
    }
}

发布事件

@PostMapping("/login")
public UserVO login(String username,String password){
  
  WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext();
  context.publishEvent(new ApiEvent(this,"用户登录"));
  
  UserVO dto = service.login(username,password);
  return dto;
}

在接口中通过WebApplicationContextUtils获取WebApplicationContext,通过publishEvent()方法发布ApiEvent事件。

程序改进

  • Spring提供了注解@EventListener简化监听器
  • 异步执行事件
  • 多个监听器监听同一个事件时,按顺序执行
  • 使用自Annotation+AOP的方式,简化事件发布

@EventListener注解,定义监听器

@EventListener标记在方法上,表示该方法是一个监听器。如果该方法只监听一个事件,可使用方法签名的方式监听事件

@EventListener
public void ApiEventListener(ApiEvent event){
  logger.info("收到Api调用事件,内容 {} ",event.getContent());
}

如果被注解的方法需要处理多种类型的事件,如Api调用事件,Log记录事件等,需要使用Classes属性。如果Classes指定了多个值,那么,被标记的方法不能有任何参数。

@EventListener({EventA.class, EventB.class})
public void ApiEventListener(ApiEvent event){
  logger.info("收到事件");
}

这样一来,我们就不能处理事件带来的附加信息。所以,建议为每个事件单独定义一个处理器。

@Async注解,定义异步

默认情况,事件时同步的,及只有当监听器的处理方法执行完成后,才会执行剩下的步骤。对于耗时很长且不影响后续业务的方法(如:将事件记录到数据库中),可以使用异步的方式处理事件。

@Async
@EventListener
public void ApiEventListener(ApiEvent event){
  logger.info("收到Api调用事件,内容 {} ",event.getContent());
}

使用 @Async 标记事件处理器为异步方法。

默认情况下,Spring没有开启Async,使用 @EnableAsync 注解使 @Async 有效。

@Order注解,定义监听器的执行顺序

可以使用 @Order(100) 注解来标记事件的监听执行顺序,异步的情况下只保证按顺序将监听器丢入进线程池。

@Async
@Order(100)
@EventListener
public void ApiEventListener(ApiEvent event){
  logger.info("收到Api调用事件,内容 {} ",event.getContent());
}

@Async
@Order(101)
@EventListener
public void ApiEventListener2(ApiEvent event){
  logger.info("收到Api调用事件,内容 {} ",event.getContent());
}

使用AOP简化事件发布

首先,我们自定义一个注解ApiLog

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiLog {

    /**
     * 描述
     *
     * @return {String}
     */
    String value() default "";
}

再定义一个切面

public class ApiLogAspect {

    @Around("@annotation(apiLog)")
    public Object around(ProceedingJoinPoint point, ApiLog apiLog) throws Throwable {
        //执行方法
        Object result = point.proceed();
    
        //记录日志
    WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext();
    context.publishEvent(new ApiEvent(this,apiLog.value()));
    
        return result;
    }
}

改造接口方法

@ApiLog("用户登录")
@PostMapping("/login")
public UserVO login(String username,String password){
  
  UserVO dto = service.login(username,password);
  return dto;
}

相关文章

网友评论

      本文标题:Spring事件监听

      本文链接:https://www.haomeiwen.com/subject/eivccktx.html