spring event的事件驱动模型和异步方法@Async

我们知道观察者模式可以实现代码的解耦,而spring的event模型就是这种设计模式的极佳体现。一个事件包含:事件发布、监听、和事件源。在spring中我们可以通过ApplicationContext的publishEvent方法去发布事件;通过实现实现ApplicationListener接口来自定义自己的监听器;继承ApplicationEvent类来实现事件源。下面以一个实例来说明:

1.spring下使用event模型

1.1 定义event

/**
 * event的基类
 *
 * @author 94977
 * @create 2018/7/22
 */
public abstract class BaseEvent extends ApplicationEvent {

    private static final long serialVersionUID = 895628808370649881L;

    public BaseEvent(Object source) {
        super(source);
    }
}
public class FaceEvent extends BaseEvent {

    private static final long serialVersionUID = -6574102695264647771L;

    /**
    * @author 94977
    * @time 2018/7/22 15:50
    * @param * @param null
    * @return
    * @description  必须要实现的构造方法
    */
    public FaceEvent(User user) {
        super(user);
    }
}

1.2 event的监听处理类。监听类实现ApplicationListener 里onApplicationEvent方法即可

@Component
public class FaceEventListener extends BaseEventListener implements ApplicationListener {

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if(event instanceof FaceEvent){
            User user = (User) event.getSource();
            LOGGER.info("===> 收到人脸事件:  {}",user);
            // .....
            System.out.println("人脸事件处理结束。。。");
        }
    }
}

当然通过event instanceof FaceEvent判断事件源来处理的方式不是很优雅。有更好的方式,接口ApplicationListener支持泛型,可以通过泛型来判断处理的事件源。如下只处理FaceEvent源。

@Component
public class FaceEventListener extends BaseEventListener implements ApplicationListener<FaceEvent> {

    @Override
    public void onApplicationEvent(FaceEvent event) {
        User user = (User) event.getSource();
        LOGGER.info("===> 收到人脸事件:  {}",user);
        // .....
        System.out.println("人脸事件处理结束。。。");

    }
}

1.3 发布事件

@Service
public class FaceHandler {

    @Autowired
    private ApplicationContext applicationContext;

    public void handle(){
        User user = new User();
        user.setAge(34);
        user.setUsername("人脸事件");
        user.setHobby("抓拍");
        //发布事件
        applicationContext.publishEvent(new FaceEvent(user));
        //进行其他业务处理
    }

以上即可。

1.4 如果要实现有序的监听,方式如下:即实现SmartApplicationListener 接口即可。

@Component
public class FaceEventListener2 extends BaseEventListener implements SmartApplicationListener {

        /**
        * @description  用于指定支持的事件类型,只有支持的才调用onApplicationEvent;
        */
        @Override
        public boolean supportsEventType(final Class<? extends ApplicationEvent> eventType) {
            return eventType == FaceEvent.class;
        }

        /**
        * @description  supportsSourceType:支持的目标类型,只有支持的才调用onApplicationEvent;
        */
        @Override
        public boolean supportsSourceType(final Class<?> sourceType) {
            return sourceType == String.class;
        }

        @Override
        public void onApplicationEvent(final ApplicationEvent event) {
            System.out.println("收到内容:" + event.getSource());
        }

    /**
     * 即顺序,越小优先级越高
     */
    @Override
        public int getOrder() {
            return 2;
        }
}

2.evnet模型的关键点

  • 事件没要处理的监听器,就会被抛弃。
  • 一个事件可以同时被多个监听处理类监听处理。
  • 以上处理事件都是同步的,如果发布事件处的业务存在事务,监听器处理也会在相同的事务中。这个一定要注意!如果对于事件的处理不想受到影响,可以onApplicationEvent方法上加@Aync支持异步。
  • 原理部分可以参考 博客 事件体系

3. 异步方法的实现

在spring中,通过在方法上添加注解@Async,可以通过executor完成异步处理此方法。注意还要添加@EnableAsync来开启异步任务的支持。
如果不自定义线程池,会使用spring的默认Executor,我们可以自定义线程池。

@Configuration
public class TaskExecutorConfig {

    @Bean("TaskExecutor")
    public Executor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(5);
        taskExecutor.setMaxPoolSize(15);
        taskExecutor.setQueueCapacity(6000);
        taskExecutor.initialize();
        return taskExecutor;
    }
}

猜你喜欢

转载自blog.csdn.net/java_collect/article/details/81156529