• 监听器模式


    监听器模式:监听事件的触发,然后做出相应的操作。

    当系统运行某些关键节点的时候,会通过广播器去发布一些事件,而系统中存在着一些监听器。对某些事件感兴趣,去订阅这些事件。当这些事件被发布出去之后,监听器监听到这些事件,会触发一些行为。

    Spring中的监听器实现

      事件(Event):即监听什么。如任务即将执行、任务执行完毕

      监听器(Listener):谁来监听

      广播器(Multicaster):发布事件、添加/移除监听器

      事件触发机制:事件什么时候发布

     

    源码:

      1、事件Event

       在Spring最顶层的是EventObject类,它代表的是一个事件对象;抽象类ApplicationEvent继承自EventObject,表示的是一个应用事件

      EventObject:

    public class EventObject implements java.io.Serializable {
        private static final long serialVersionUID = 5516075349620653480L;
        
        protected transient Object  source;
    
        public EventObject(Object source) {
            if (source == null)
                throw new IllegalArgumentException("null source");
    
            this.source = source;
        }
    
    }

      ApplicationEvent:

    public abstract class ApplicationEvent extends EventObject {
    
        /** System time when the event happened. */
        private final long timestamp;
    
    
        /**
         * Create a new ApplicationEvent.
         * @param source the object on which the event initially occurred (never {@code null})
         */
        public ApplicationEvent(Object source) {
            super(source);
            this.timestamp = System.currentTimeMillis();
        }
    
    }

      2、监听器

      ApplicationListener继承自EventListener,EventListener 是一个空接口,用来声明这是一个事件监听的接口。

      ApplicationListener:

    @FunctionalInterface
    public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    
        /**
         * Handle an application event.
         * @param event the event to respond to
         */
        void onApplicationEvent(E event); // 监听到事件发生的时候,去做一些事情
    
    }

    ApplicationListener的泛型继承自ApplicationEvent,因此在实现这个接口的时候,可以声明自己监听的具体事件。

    系统在触发这个系统监听器的时候会根据其监听的事件做一个过滤。

      3、广播器

      系统广播器是 ApplicationEventMulticaster ,实现这个接口来管理一些应用监听器,并且广播事件。

      其中定义了添加、删除监听器以及广播事件的方法。

      ApplicationEventMulticaster :

    public interface ApplicationEventMulticaster {
    
        /**
         * Add a listener to be notified of all events.
         * @param listener the listener to add
         */
        void addApplicationListener(ApplicationListener<?> listener);
    
        /**
         * Add a listener bean to be notified of all events.
         * @param listenerBeanName the name of the listener bean to add
         */
        void addApplicationListenerBean(String listenerBeanName);
    
        /**
         * Remove a listener from the notification list.
         * @param listener the listener to remove
         */
        void removeApplicationListener(ApplicationListener<?> listener);
    
        /**
         * Remove a listener bean from the notification list.
         * @param listenerBeanName the name of the listener bean to add
         */
        void removeApplicationListenerBean(String listenerBeanName);
    
        /**
         * Remove all listeners registered with this multicaster.
         * <p>After a remove call, the multicaster will perform no action
         * on event notification until new listeners are being registered.
         */
        void removeAllListeners();
    
        /**
         * Multicast the given application event to appropriate listeners.
         * <p>Consider using {@link #multicastEvent(ApplicationEvent, ResolvableType)}
         * if possible as it provides a better support for generics-based events.
         * @param event the event to multicast
         */
        void multicastEvent(ApplicationEvent event);
    
        /**
         * Multicast the given application event to appropriate listeners.
         * <p>If the {@code eventType} is {@code null}, a default type is built
         * based on the {@code event} instance.
         * @param event the event to multicast
         * @param eventType the type of event (can be null)
         * @since 4.2
         */
        void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
    
    }

      4、ApplicationListener监听器注册到Spring容器

      1)启动类:

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

      2)调用run方法会先创建SpringApplication对象然后调用其run方法;SpringApplication#run 1258

       public static ConfigurableApplicationContext run(Class<?>[] primarySources,
                String[] args) {
            return new SpringApplication(primarySources).run(args);
        }
    
       // SpringApplication 构造方法
        public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
            this.resourceLoader = resourceLoader;
            Assert.notNull(primarySources, "PrimarySources must not be null");
            this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
            this.webApplicationType = WebApplicationType.deduceFromClasspath();
            setInitializers((Collection) getSpringFactoriesInstances(
                    ApplicationContextInitializer.class));
            setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 将监听器对应添加到 private List<ApplicationListener<?>> listeners 中
            this.mainApplicationClass = deduceMainApplicationClass();
        }

    getSpringFactoriesInstances 方法获取到所有ApplicationListener的实现,并创建对象,然后排序。

    setListeners 方法:

        public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
            this.listeners = new ArrayList<>(); // 先初始化SpringApplication的 private List<ApplicationListener<?>> listeners; 属性
            this.listeners.addAll(listeners); // 将getSpringFactoriesInstances返回的对象集合添加进去
        }

      5、广播器初始化并添加监听器到广播器中

      1)广播器初始化

        AbstractApplicationContext#refresh#initApplicationEventMulticaster()  537行

      2)添加监听器到广播器中

        AbstractApplicationContext#refresh#registerListeners()   543行

       6、事件触发机制

      SpringApplication#run 295

     301行:获取到所有实现 SpringApplicationRunListener 接口的监听器, 创建对象并添加到SpringApplicationRunListeners类的 List<SpringApplicationRunListener> listeners 属性中。

      SpringApplicationRunListener接口中定义了Spring容器启动过程中各个阶段的事件,比如starting、environmentPrepared、contextPrepared、contextLoaded、started、running、failed。

      所以只用调用不同的方法就可以在相应的节点触发对应的事件。

      比如:SpringApplicationRunListeners#statrting() ,遍历所有的SpringApplicationRunListener类型的监听器并调用其 starting() 方法

      

     又比如 SpringApplicationRunListener 接口的实现类 EventPublishingRunListener 的 starting() 实现:  

      

     调用广播器的 multicastEvent 方法发送一个相应的 ApplicationStartingEvent 事件。

     multicastEvent() 方法的内部实现:

        @Override
        public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
            ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
           // 获取对当前事件监听的监听器列表,然后遍历
            for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { 
                Executor executor = getTaskExecutor(); // 获取线程池
                if (executor != null) {
                    executor.execute(() -> invokeListener(listener, event));
                }
                else {
                    invokeListener(listener, event); // 调用监听器的onApplicationEvent()方法,触发事件
                }
            }
        }    

    那么,getApplicationListeners() 方法是如何获取对指定时间监听的监听器的?

    大致就是判断监听器的泛型的类型,是否与发布事件的类型一致,如果一致将监听器的对象放到一个集合中。

     模拟Spring自实现监听器

     1、事件 抽象类Event,其他要监控的事件继承它

    /**
     * 事件
     *
     * @author yangyongjie
     * @date 2020/9/30
     * @desc
     */
    public abstract class Event<T> {
        /**
         * 事件自身资源
         */
        protected T source;
        /**
         * 事件发生时间
         */
        private final long timestamp;
    
        public Event(T source) {
            this.source = source;
            this.timestamp = System.currentTimeMillis();
        }
    
        public T getSource() {
            return source;
        }
    
        public void setSource(T source) {
            this.source = source;
        }
    
        public long getTimestamp() {
            return timestamp;
        }
    }

    如:流程结束事件

    /**
     * 审批流程结束事件
     *
     * @author yangyongjie
     * @date 2020/10/15
     * @desc
     */
    public class AuditFlowFinishEvent extends Event<AuditFlow> {
    
        public AuditFlowFinishEvent(AuditFlow auditFlow) {
            super(auditFlow);
        }
    
    }

     2、监听器接口 Listener,自定义监听器实现它;泛型表示要监听的事件

    /**
     * 监听器
     *
     * @author yangyongjie
     * @date 2020/9/30
     * @desc
     */
    public interface Listener<E extends Event> {
    
        /**
         * 当事件发生做一些事情
         *
         * @param event
         */
        void onEvent(E event);
    }

    如:审核流程结束监听器

    /**
     * 审核流程结束监听器
     *
     * @author yangyongjie
     * @date 2020/10/15
     * @desc
     */
    @Component
    public class AuditFlowFinishListener implements Listener<AuditFlowFinishEvent> {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(AuditFlowFinishListener.class);
    
        @Override
        public void onEvent(AuditFlowFinishEvent event) {
            AuditFlow auditFlow = event.getSource();
            LOGGER.info("流程结束监听器工作了!");
        }
    }

    3、广播器,管理监听器,发布事件

    广播器接口:

    /**
     * 事件广播器
     *
     * @author yangyongjie
     * @date 2020/9/30
     * @desc
     */
    public interface EventMulticaster {
    
        /**
         * 添加监听器
         *
         * @param listener
         */
        void addListener(Listener<?> listener);
    
        /**
         * 移除监听器
         *
         * @param listener
         */
        void removeListener(Listener<?> listener);
    
        /**
         * 发布事件
         *
         * @param event
         */
        void multicastEvent(Event event);
    
    }

    广播器实现类:

    /**
     * 广播器(事件发布器)
     *
     * @author yangyongjie
     * @date 2020/10/15
     * @desc
     */
    @Component
    public class SimpleEventMulticaster implements EventMulticaster, ApplicationContextAware {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(SimpleEventMulticaster.class);
    
        private final Set<Listener<?>> listeners = new LinkedHashSet<>();
    
        /**
         * 创建一个执行监听器线程池,核心线程数为1,最大线程数为5,线程空闲时间为60s,拒绝策略为打印日志并直接执行被拒绝的任务
         */
        private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(1, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(50), new CustomThreadFactory("simpleEventMulticaster"), (r, executor) -> {
            LOGGER.error("Task:{},rejected from:{}", r.toString(), executor.toString());
            // 直接执行被拒绝的任务,JVM另起线程执行
            r.run();
        });
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            // 获取容器中实现Listener接口的监听器,并添加到listeners缓存中
            Map<String, Listener> listenerMap = applicationContext.getBeansOfType(Listener.class);
            for (Map.Entry<String, Listener> entry : listenerMap.entrySet()) {
                addListener(entry.getValue());
            }
        }
    
        @Override
        public void addListener(Listener<?> listener) {
            this.listeners.add(listener);
        }
    
        @Override
        public void removeListener(Listener<?> listener) {
            this.listeners.remove(listener);
        }
    
        @Override
        public void multicastEvent(Event event) {
            Class eventClass = event.getClass();
            Set<Listener> interestedListeners = getInterestedListeners(eventClass);
            // 事件发生,异步调用监听器的事件处理方法
            for (Listener listener : interestedListeners) {
                EXECUTOR.execute(() -> listener.onEvent(event));
            }
        }
    
        /**
         * 获取对当前事件感兴趣的监听器
         *
         * @param eventClass
         */
        private Set<Listener> getInterestedListeners(Class eventClass) {
            // 存放监听对发布事件感兴趣的监听器
            Set<Listener> interestedListeners = new LinkedHashSet<>();
            for (Listener listener : listeners) {
                // 获取监听器的泛型类型
                ParameterizedType parameterizedType = (ParameterizedType) listener.getClass().getGenericInterfaces()[0];
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                Listener filterListener = null;
                for (Type actualTypeArgument : actualTypeArguments) {
                    if (StringUtils.equals(eventClass.getName(), actualTypeArgument.getTypeName())) {
                        filterListener = listener;
                    }
                }
                if (filterListener != null) {
                    interestedListeners.add(filterListener);
                }
            }
            return interestedListeners;
        }
    
    }

    4、使用广播器发布事件

     AuditFlowFinishEvent auditFlowFinishEvent = new AuditFlowFinishEvent(new AuditFlow());
     simpleEventMulticaster.multicastEvent(auditFlowFinishEvent);

    END.

      

  • 相关阅读:
    【移动安全高级篇】————2、浅谈Android软件安全自动化审计
    【移动安全实战篇】————1、Android手机下xx.apk JAVA破解之旅
    【移动安全高级篇】————1、Android沙盘原理与实现
    CLR
    反射
    泛型
    面试
    Sqlite
    粒子
    地图
  • 原文地址:https://www.cnblogs.com/yangyongjie/p/13750487.html
Copyright © 2020-2023  润新知