Spring的ApplicationEvent简单使用

ApplicationEvent以及Listener是Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式,设计初衷也是为了系统业务逻辑之间的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。

创建Event事件

public class MessageEvent extends ApplicationEvent {

    /**
     * 消息体
     */
    private MessageDTO messageDTO;

    /**
     * Create a new ApplicationEvent.
     *
     * @param source the object on which the event initially occurred (never {@code null})
     */
    public MessageEvent(MessageDTO source) {
        super(source);
        this.messageDTO = source;
    }

    public MessageDTO getMessageDTO() {
        return messageDTO;
    }
}

我们自定义事件MessageEvent继承了ApplicationEvent,继承后必须重载构造函数,构造函数的参数可以任意指定,其中source参数指的是发生事件的对象,该对象可以在监听内被获取。

在Spring内部中有多种方式实现监听如:@EventListener注解、实现ApplicationListener泛型接口、实现SmartApplicationListener接口等,我们下面来讲解下这三种方式分别如何实现。

创建MessageDTO

public class MessageDTO {

    /**
     * 消息类型
     */
    private MsgTypeEnum msgType;

    /**
     * 消息发出时的时间戳
     */
    private Long syncTime;
}

事件发布

@Service
public class UserService
{
    @Autowired
    ApplicationContext applicationContext;

    public void register()
    {
        //../省略其他逻辑

        //发布事件
        applicationContext.publishEvent(new MessageEvent(new MessageDTO()));
    }
}

事件发布是由ApplicationContext对象管控的,我们发布事件前需要注入ApplicationContext对象调用publishEvent方法完成事件发布。

实现监听

@EventListener
@Service
public class MessageEventService {

    @EventListener
    public void notify(MessageEvent messageEvent) {
        log.info("异步发送消息体:{}", JSON.toJSONString(messageEvent));
       
    }
}
ApplicationListener
@Component
public class RegisterListener implements ApplicationListener<MessageEvent>
{
    /**
     * 实现监听
     */
    @Override
    public void onApplicationEvent(MessageEvent messageEvent) {
        
    }
}
SmartApplicationListener实现有序监听
@Component
public class UserRegisterListener implements SmartApplicationListener
{
    /**
     *  该方法返回true&supportsSourceType同样返回true时,才会调用该监听内的onApplicationEvent方法
     * @param aClass 接收到的监听事件类型
     * @return
     */
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
        //只有MessageEvent监听类型才会执行下面逻辑
        return aClass == MessageEvent.class;
    }

    /**
     *  该方法返回true&supportsEventType同样返回true时,才会调用该监听内的onApplicationEvent方法
     * @param aClass
     * @return
     */
    @Override
    public boolean supportsSourceType(Class<?> aClass) {
        //只有在UserService内发布的MessageEvent事件时才会执行下面逻辑
        return aClass == UserService.class;
    }

    /**
     *  supportsEventType & supportsSourceType 两个方法返回true时调用该方法执行业务逻辑
     * @param applicationEvent 具体监听实例,这里是UserRegisterEvent
     */
    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {

        //转换事件类型
        MessageEvent messageEvent = (MessageEvent) applicationEvent;
       
    }

    /**
     * 同步情况下监听执行的顺序
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

SmartApplicationListener接口继承了全局监听ApplicationListener,并且泛型对象使用的ApplicationEvent来作为全局监听,可以理解为使用SmartApplicationListener作为监听父接口的实现,监听所有事件发布。

既然是监听所有的事件发布,那么SmartApplicationListener接口添加了两个方法supportsEventType、supportsSourceType来作为区分是否是我们监听的事件,只有这两个方法同时返回true时才会执行onApplicationEvent方法。

可以看到除了上面的方法,还提供了一个getOrder方法,这个方法就可以解决执行监听的顺序问题,return的数值越小证明优先级越高,执行顺序越靠前。

如果说我们不希望在执行监听时等待监听业务逻辑耗时,发布监听后立即要对接口或者界面做出反映,我们该怎么做呢?

 使用@Async实现异步监听

@Aysnc其实是Spring内的一个组件,可以完成对类内单个或者多个方法实现异步调用,这样可以大大的节省等待耗时。内部实现机制是线程池任务ThreadPoolTaskExecutor,通过线程池来对配置@Async的方法或者类做出执行动作。

线程任务池配置

我们创建一个ListenerAsyncConfiguration,并且使用@EnableAsync注解开启支持异步处理,具体代码如下所示:

@Configuration
@EnableAsync
public class ListenerAsyncConfiguration implements AsyncConfigurer
{
    /**
     * 获取异步线程池执行对象
     * @return
     */
    @Override
    public Executor getAsyncExecutor() {
        //使用Spring内置线程池任务对象
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        //设置线程池参数
        taskExecutor.setCorePoolSize(5);
        taskExecutor.setMaxPoolSize(10);
        taskExecutor.setQueueCapacity(25);
        taskExecutor.initialize();
        return taskExecutor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return null;
    }
}

我们自定义的监听异步配置类实现了AsyncConfigurer接口并且实现内getAsyncExecutor方法以提供线程任务池对象的获取。
我们只需要在异步方法上添加@Async注解就可以实现方法的异步调用

@Service
public class MessageEventService {

    @EventListener
    @Async
    public void notify(MessageEvent messageEvent) {
        log.info("异步发送消息体:{}", JSON.toJSONString(messageEvent));
       
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值