Spring event应用

当我们在实现某些特定业务逻辑时,通常会通过发送事件的方式实现代码解耦,这也是观察者模式的一种体现。从spring 3.0.5为我们实现了用annotation实现event和eventListner。
一个事件包含:事件发布、监听、和事件源。在spring中我们可以通过ApplicationContext的publishEvent方法去发布事件;通过实现实现ApplicationListener接口来自定义自己的监听器;继承ApplicationEvent类来实现事件源。下面以一个实例来说明:
定义一个事件A事件源:

package cn.slimsmart.spring.demo.event;

import org.springframework.context.ApplicationEvent;

//A事件
public class AEvent extends ApplicationEvent{

    private static final long serialVersionUID = 1L;

    private String name = "AAAA";
    public String getName() {
        return name;
    }

    public AEvent(Object source) {
        super(source);
    }
}

监听事件A:

@Component
public class AEventListener implements ApplicationListener{

    public void onApplicationEvent(ApplicationEvent event) {
        System.err.println(this.getClass().getName());
        if(event instanceof AEvent){
            //处理事件A业务逻辑
        }
        System.out.println(event.getSource());
    }
}

发布事件:

applicationContext.publishEvent(new AEvent("testA"));

从上面的监听器处理可以看出,需要通过event instanceof AEvent判断事件源来处理对于的业务逻辑,这样很不爽,当然有更好的方式。接口ApplicationListener支持泛型,可以通过泛型来判断处理的事件源。如下只处理BEvent源。

@Component
public class BEventListener implements ApplicationListener<BEvent>{

    public void onApplicationEvent(BEvent bEvent) {
        System.out.println("event name : "+bEvent.getName());
        System.out.println(bEvent.getSource());
    }
}

如果事件没要处理的监听器,就会被抛弃。
以上处理事件都是同步的,如果发布事件处的业务存在事务,监听器处理也会在相同的事务下。
如果是发送邮箱、短信等耗时操作,如何让事件异步处理呢?
1、全局异步配置

<!-- 配置线程池 :
    pool-size="1-3" 表示线程池活跃的线程数为1,最大线程数为3
    queue-capacity="20" 表示任务队列的最大容量
     -->
    <task:executor id="executor" pool-size="3" queue-capacity="20" />
    <!-- 名字必须是applicationEventMulticaster和messageSource是一样的,默认找这个名字的对象 -->
    <!-- 名字必须是applicationEventMulticaster,因为AbstractApplicationContext默认找个 -->
    <!-- 如果找不到就new一个,但不是异步调用而是同步调用 -->
    <bean id="applicationEventMulticaster"
        class="org.springframework.context.event.SimpleApplicationEventMulticaster">
        <!-- 注入任务执行器 这样就实现了异步调用(缺点是全局的,要么全部异步,要么全部同步(删除这个属性即是同步)) -->
        <property name="taskExecutor" ref="executor" />
    </bean>

通过注入taskExecutor来完成异步事件调用。不推荐全局配置。
2、@Aync注解来完成异步调用
spring3提供了@Aync注解来完成异步调用。不仅支持异步调用,还支持简单的任务调度。

    <!-- 开启@AspectJ AOP代理 -->
    <aop:aspectj-autoproxy proxy-target-class="true" />
    <!-- 任务调度器配置 -->
    <task:scheduler id="scheduler" pool-size="10" />
    <!-- 任务执行器配置 -->
    <task:executor id="executor" pool-size="10" />
    <!--开启注解调度支持 @Async @Scheduled -->
    <task:annotation-driven executor="executor" proxy-target-class="true"  scheduler="scheduler"  />

如上配置,在任何方法增加@Aync注解都会异步执行,通过executor完成异步处理。通过方法增加@Scheduled注解完成任务调度。
对于事件的处理可以onApplicationEvent方法上加@Aync支持异步。
@Aync注解的应用范围:
类:表示这个类中的所有方法都是异步的
方法:表示这个方法是异步的,如果类也注解了,则以这个方法的注解为准
上面的配置可以简化只配置:<task:annotation-driven />默认会有缺省的executor。
注:在spring boot 开启异步配置在配置类中添加注解@EnableAsync 。

猜你喜欢

转载自blog.csdn.net/tianwei7518/article/details/72720287