zoukankan      html  css  js  c++  java
  • spring 事件监听同时支持同步事件及异步事件

    spring的事件监听机制这里就不再赘述了,不清楚的可以自行google,我们知道,事件发布是依靠调用实现了ApplicationEventPublisher接口类的publishEvent方法进行发布事件,而publishEvent 方法又是通过调用实现了ApplicationEventMulticaster接口的类的multicastEvent方法进行事件的广播的,ApplicationEventMulticaster中保存了所有的实现了ApplicationListener接口的监听器,我们看一下spring内部实现ApplicationEventMulticaster接口的一个广播器SimpleApplicationEventMulticaster的源码

    public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
        private Executor taskExecutor;
    
        public SimpleApplicationEventMulticaster() {
        }
    
        public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
            this.setBeanFactory(beanFactory);
        }
    
        public void setTaskExecutor(Executor taskExecutor) {
            this.taskExecutor = taskExecutor;
        }
    
        protected Executor getTaskExecutor() {
            return this.taskExecutor;
        }
    
        public void multicastEvent(final ApplicationEvent event) {
            Iterator i$ = this.getApplicationListeners(event).iterator();
    
            while(i$.hasNext()) {
                final ApplicationListener listener = (ApplicationListener)i$.next();
                Executor executor = this.getTaskExecutor();
                if (executor != null) {
                    executor.execute(new Runnable() {
                        public void run() {
                            listener.onApplicationEvent(event);
                        }
                    });
                } else {
                    listener.onApplicationEvent(event);
                }
            }
    
        }
    }

    可以看到,异步事件通知主要依靠SimpleApplicationEventMulticaster 类中的Executor去实现的,如果这个变量不配置的话默认事件通知是同步的, 否则就是异步通知了,要实现同时支持同步通知和异步通知就得从这里下手;

    我的实现方式是为每个监听方法加个自定义注解,然后在multicastEvent方法中获取对应监听器上的注解,根据注解去决定是同步通知还是异步通知,这样就可以同时支持了,废话不多说,直接看代码

    /**
     * event listener 专用注解,只能加在实现了ApplicationListener 的onApplicationEvent方法上
     * 用来标识是同步监听还是异步监听
     */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface EventType {
        EventTypeEnum value() default EventTypeEnum.ASYNC;
    }
    /**
     * @Description: 事件监听枚举类
     * @Author Mr.huang
     * @Date 2020/3/20 0020
     * @Version V1.0
     **/
    public enum  EventTypeEnum {
        ASYNC,  //异步
        SYNC;   //同步
    }
    /**
     * @Description: 事件广播基础类,支持自定义注解实现同步或异步的事件监听
     * @Author Mr.huang
     * @Date 2020/3/20 0020
     * @Version V1.0
     **/
    public class BaseApplicationEventMulticaster extends SimpleApplicationEventMulticaster {
        private static Logger log = LoggerFactory.getLogger(BaseApplicationEventMulticaster.class);
        @SuppressWarnings("unchecked")
        public void multicastEvent(final ApplicationEvent event) {
            //默认异步
            EventTypeEnum defaultEventType = EventTypeEnum.ASYNC;
            for (final ApplicationListener listener : getApplicationListeners(event)) {
                try {
                    Class listenerClass = Class.forName(listener.getClass().getName());
                    if(listenerClass!=null){
                        Method onApplicationEventMethod = listenerClass.getMethod("onApplicationEvent",ApplicationEvent.class);
                        if(onApplicationEventMethod.isAnnotationPresent(EventType.class)){
                            //获取该元素上指定类型的注解
                            EventType eventMethodAnnotation = onApplicationEventMethod.getAnnotation(EventType.class);
                            defaultEventType = eventMethodAnnotation.value();
                        }
                    }
                } catch (Exception e) {
                    log.error("获取监听类实例出错~");
                }
    
                Executor executor = getTaskExecutor();
                if (executor != null&&defaultEventType==EventTypeEnum.ASYNC) {
                    executor.execute(new Runnable() {
                        public void run() {
                            listener.onApplicationEvent(event);
                        }
                    });
                }
                else {
                    listener.onApplicationEvent(event);
                }
            }
        }
    }

    最后在实现了ApplicationListener接口类中的onApplicationEvent方法上加上注解即可

    /**
     * @Description: TODO
     * @Author Mr.huang
     * @Date 2020/3/21 0021
     * @Version V1.0
     **/
    public class UserChargeService implements ApplicationListener<UserChargeEvent> {
        @EventType(value = EventTypeEnum.ASYNC)
        @Override
        public void onApplicationEvent(UserChargeEvent userChargeEvent) {
            //业务逻辑
        }
    }
  • 相关阅读:
    HTML5 GAME TUTORIAL(三): Draw shapes, paths and text(译)
    HTML5 GAME TUTORIAL(二): Set-up an HTML5 canvas(译)
    HTML5 GAME TUTORIAL(一): Develop an HTML5 game(译)
    实现一个扇形的几种方法
    What Is Webpack and How Does It Work(译)
    What Does Webpack Do, and How Do I Use It for My Website?(译)
    Getting Started with NestJS(译)
    vue 渲染出来的列表点击的时候需要单独给li添加一个class
    移动端使用isscroll.js input无法获取焦点(就是点了没反应啦!)
    移动端适配之rem 笔记
  • 原文地址:https://www.cnblogs.com/angryprogrammer/p/12536752.html
Copyright © 2011-2022 走看看