监听器模式

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

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

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.

  

原文地址:https://www.cnblogs.com/yangyongjie/p/13750487.html