天天看點

關于Spring的事件監聽機制,你知道多少?

作者:小心程式猿QAQ

前言

前一節,我們了解了Spring 提供的 Aware接口,我們可以通過這個實作這個接口的一些類擷取到我們需要的東西。具體内容見前一節。 Spring 也提供了一種單機的事件機制。可以通過發送、監聽,來實作一些異步操作。 使用這種 類似 MQ 的事件機制,我們可以通過 這個事件機制來完成一些自己的業務操作。在我們使用spring提供的事件機制時,我們隻需要關注自己的事件,和自己的事件處理器。所有的事件都會繼承 ApplicationEvent,然後再完成對于自己時間的監聽器,監聽器都 實作 ApplicationListener接口,實作 onApplicationEvent方法,來處理監聽到的事件。 下面是事件注冊、監聽的整體過程。主要就是 在spring容器加載的時候,把所有的監聽器統一注冊到SimpleApplicationEventMulticaster事件分發器中,然後統一處理。

關于Spring的事件監聽機制,你知道多少?
關于Spring的事件監聽機制,你知道多少?

實作

ApplicationEvent 事件基類, EventObject是java提供的一個類

public class ApplicationEvent extends EventObject {
    /**
     * Constructs a prototypical Event.
     *
     * @param source The object on which the Event initially occurred.
     * @throws IllegalArgumentException if source is null.
     */
    public ApplicationEvent(Object source) {
        super(source);
    }
}
複制代碼           

ApplicationContextEvent系統事件

public class ApplicationContextEvent extends ApplicationEvent {
    /**
     * Constructs a prototypical Event.
     *
     * @param source The object on which the Event initially occurred.
     * @throws IllegalArgumentException if source is null.
     */
    public ApplicationContextEvent(ApplicationContext source) {
        super(source);
    }


    public final ApplicationContext getApplicationContext() {
        return (ApplicationContext) getSource();
    }
}
複制代碼           

ApplicationEventPublisher 事件釋出器,統一釋出事件。

public interface ApplicationEventPublisher {

    /**
     * 釋出事件
     * @param event 事件
     */
    void publishEvent(ApplicationEvent event);

}
複制代碼           

ApplicationEventMulticaster事件管理、分發器。ApplicationEventMulticaster統一定義公共行為, AbstractApplicationEventMulticaster抽象類處理公共邏輯。SimpleApplicationEventMulticaster預設分發器,隻需要執行具體的分發邏輯。supportEvent方法檢查事件是否需要被處理。

public interface ApplicationEventMulticaster {

    /**
     * Add a listener to be notified of all events.
     * @param listener the listener to add
     */
    void addApplicationListener(ApplicationListener listener);

    /**
     * Remove a listener from the notification list.
     * @param listener the listener to remove
     */
    void removeApplicationListener(ApplicationListener listener);

    /**
     * Multicast the given application event to appropriate listeners.
     * @param event the event to multicast
     */
    void multicastEvent(ApplicationEvent event);

}

public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {

    private final Set<ApplicationListener> applicationListeners = new LinkedHashSet<>();

    private BeanFactory beanFactory;

    @Override
    public void addApplicationListener(ApplicationListener listener) {
        this.applicationListeners.add((ApplicationListener) listener);
    }

    @Override
    public void removeApplicationListener(ApplicationListener listener) {
        this.applicationListeners.remove(listener);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event) throws BeansException {
        LinkedList<ApplicationListener<?>> allListeners = new LinkedList<>();
        for (ApplicationListener<?> listener : applicationListeners) {
            if (supportEvent(listener, event)) {
                allListeners.add(listener);
            }
        }
        return allListeners;
    }

    /**
     * 監聽器是否對該事件感興趣
     */
    protected boolean supportEvent(ApplicationListener listener, ApplicationEvent event) throws BeansException {
        // 檢查事件是否需要關注
        Class<? extends ApplicationListener> clazz = listener.getClass();
        Class<?> targetClass = ClassUtils.isCglibProxyClass(clazz) ? clazz.getSuperclass() : clazz;
        Type genericInterface = targetClass.getGenericInterfaces()[0];
        Type typeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];
        String className = typeArgument.getTypeName();
        Class<?> eventClassName;
        try {
            eventClassName = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new BeansException("wrong event class name: " + className);
        }
        // 判定此 eventClassName 對象所表示的類或接口與指定的 event.getClass() 參數所表示的類或接口是否相同,或是否是其超類或超接口。
        // isAssignableFrom是用來判斷子類和父類的關系的,或者接口的實作類和接口的關系的,預設所有的類的終極父類都是Object。如果A.isAssignableFrom(B)結果是true,證明B可以轉換成為A,也就是A可以由B轉換而來。
        return eventClassName.isAssignableFrom(event.getClass());
    }
}

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster{
    @Override
    public void multicastEvent(ApplicationEvent event) {
        try {
            // 實作事件處理
            Collection<ApplicationListener<?>> listeners = getApplicationListeners(event);
            for (ApplicationListener listener : listeners) {
                listener.onApplicationEvent(event);
            }
        }catch (Exception e){
            // 執行失敗
        }
    }
}
複制代碼           

AbstractApplicationContext容器重新整理,完成 事件分發器的注冊、事件監聽器的注冊。

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

    private ApplicationEventMulticaster applicationEventMulticaster;

	/**
     * 模闆方法,控制定義spring上下文的重新整理與建立
     * @throws BeansException
     */
    @Override
    public void refresh() throws BeansException {
        // 1. 建立beanFactory,加載beanDefinition
        refreshBeanFactory();
        // 2. 擷取 beanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        // 3. 添加 ApplicationContextAwareProcessor,讓繼承自 ApplicationContextAware 的 Bean 對象都能感覺所屬的 ApplicationContext
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        // 4. bean 執行個體化之前 執行 beanFactoryPostProcessor
        invokeBeanFactoryPostProcessors(beanFactory);
        // 5. beanPostProcessor 完成 bean 執行個體化後的注冊操作
        registerBeanPostProcessors(beanFactory);
        // 6. 提前執行個體化 單例bean 對象
        beanFactory.preInstantiateSingletons();
        // 初始化事件釋出者
        initApplicationEventMulticaster();
        // 注冊監聽事件
        registerListeners();
        // 完成重新整理
        finishRefresh();
    }

    private void finishRefresh() {
        publishEvent(new ContextRefreshedEvent(this));
    }

    private void registerListeners() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        Collection<ApplicationListener> listeners = beanFactory.getBeansOfType(ApplicationListener.class).values();
        for (ApplicationListener listener : listeners) {
            applicationEventMulticaster.addApplicationListener(listener);
        }
    }

    private void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        applicationEventMulticaster = new SimpleApplicationEventMulticaster();
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster);
    }


    @Override
    public void publishEvent(ApplicationEvent event) {
        applicationEventMulticaster.multicastEvent(event);
    }

}
複制代碼           

測試

定義事件、定義事件監聽器。

/**
 * @author huangle
 * @date 2023/3/14 16:21
 */
public class ConsumerEvent extends ApplicationContextEvent {

    private String msgId;

    private String msgBody;

    public ConsumerEvent(ApplicationContext source, String msgId, String msgBody) {
        super(source);
        this.msgId = msgId;
        this.msgBody = msgBody;
    }
}


public class ConsumerEventLister implements ApplicationListener<ConsumerEvent> {
    @Override
    public void onApplicationEvent(ConsumerEvent consumerEvent) {
        System.out.println(this.getClass()+"接受到消息:"+consumerEvent.getMsgId()+"-"+consumerEvent.getMsgBody());
    }
}

複制代碼           

注入事件監聽器

<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<bean id="consumerEventLister" class="cn.anoxia.springframework.beans.factory.support.event.ConsumerEventLister"/>
    <bean id="applicationRefershEventListener" class="cn.anoxia.springframework.beans.factory.support.event.ApplicationRefershEventListener"/>
    <bean id="applicationCloseEventListener" class="cn.anoxia.springframework.beans.factory.support.event.ApplicationCloseEventListener"/>
</beans>
複制代碼           

釋出事件

@Test
    public void testEvent() throws BeansException{
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
        applicationContext.publishEvent(new ConsumerEvent(applicationContext, UUID.randomUUID().toString(),"消息發送成功!"));
        applicationContext.registerShutdownHook();
    }
複制代碼           
關于Spring的事件監聽機制,你知道多少?

作者:Anoxia1

連結:https://juejin.cn/post/7225891176532770877