Spring Event使用小结

1、概览

Spring Events 是Spring Framework的一部分,但在应用程序中并不经常使用,甚至被忽略。然而,Spring的Application拥有强大的事件发布并注册事件监听器的能力,它拥有一套完整的事件发布与处理机制。Spring 4.2开始引入@EventListener注解来监听具体类型的事件,它的出现,消除了使用Spring定义一个事件监听器的复杂操作。仅仅通过一个简单的注解,就可以完成一个监听器的定义,你不需要额外的进行其他的配置;这简直太棒了。在Spring Framework中,事件的发布是由ApplicationContext提供的,如果想完成一个完整的面向事件(也称为事件驱动编程)编程,你需要遵循以下三个基本的原则:
1、定义一个事件,且扩展ApplicationEvent
2、事件发布者应该注入一个ApplicationEventPublisher对象
3、监听器实现ApplicationListener接口或者使用@EventListener注解

2、简单实践

2.1、创建自定义事件,继承ApplicationEvent

public class CustomSpringEvent extends ApplicationEvent {
    private String message;

    public CustomSpringEvent(Object source, String message) {
        super(source);
        this.message = message;
    }
    public String getMessage() {
        return message;
    }
}

2.2、创建事件发布者应该注入一个ApplicationEventPublisher对象

@Component
public class CustomSpringEventPublisher {

    private final ApplicationEventPublisher applicationEventPublisher;

    public CustomSpringEventPublisher(final ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    public void publishCustomEvent(final String message) {
        System.out.println("Publishing custom event. ");

        this.applicationEventPublisher.publishEvent(new CustomSpringEvent(this, message));
    }
}

2.3、创建监听器实现ApplicationListener接口或者使用@EventListener注解

@Component
public class CustomSpringEventListener implements ApplicationListener<CustomSpringEvent> {

    @Override
    public void onApplicationEvent(CustomSpringEvent event) {
        System.out.println("Received spring custom event - " + event.getMessage());
    }

}

@Component
public class CustomSpringEventListener {

    @EventListener(value = CustomSpringEvent.class)
    public void onApplicationEvent(CustomSpringEvent event) {
        System.out.println("Received spring custom event - " + event.getMessage());
    }

}

3、进阶

3.1、处理方式

默认使用同步处理的方式,若需实现监听器异步处理我们可以结合@Async@EnableAsync注解完成
启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class BootstrapApplication {

    public static void main(String[] args) {
        SpringApplication.run(BootstrapApplication.class, args);
    }

}

事件监听器

@Component
public class CustomSpringEventListener {

    @Async
    @EventListener(value = CustomSpringEvent.class)
    public void onApplicationEvent(CustomSpringEvent event) {
        System.out.println("Received spring custom event - " + event.getMessage());
    }

}

3.2、事务事件

Spring 事件可以和事务一起使用,但是可能会出现下面这种异常情况。例如,用户注册成功后发布通知事件,但在后续的事务处理中处理异常导致事务回滚,会出现用户收到注册成功短信但实际没有注册成功。最佳方式是将事务处理逻辑和事件发布拆分,避免上述异常场景。
当然也可以使用 TransactionalEventListener 指定和事务执行的顺序关系

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doSomething() {
        // 1、处理业务
        // 2、业务处理成功
        // 3、事件发布
        // 4、事务回滚
    }

事件监听

@Component
public class CustomSpringEventListener {

    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    @EventListener(value = CustomSpringEvent.class)
    public void onApplicationEvent(CustomSpringEvent event) {
        System.out.println("Received spring custom event - " + event.getMessage());
    }

}

4、总结

监听器默认同步执行,事件的所有监听器是同步执行的,需要评估同步阻塞对当前主流程带来的影响,建议使用异步的方式。
监听器的事件处理并不可靠,因此建议 Spring Event 应仅使用在应用程序内部组件解耦且没有可靠性要求的场景,比如消息通知等。
保持监听器的逻辑尽可能小,事件监听器的逻辑应该保持在最低限度,仅仅是充当程序内部不同部分的粘合剂,任何实质性的逻辑应该放在具体的服务类实现。
谨慎使用条件监听器和事务监听器,虽然两者都是强大的工具,但过多的使用会导致我们的程序出现难以调试的问题。

posted @ 2024-03-19 16:55  Bruce.Chang.Lee  阅读(217)  评论(0)    收藏  举报