spring中多播器与监听器

参考文章:https://www.cnblogs.com/nijunyang/p/12339757.html

自定义多播器+异步通知:https://blog.csdn.net/pengweismile/article/details/92363266

观察者模式引申:https://blog.csdn.net/weixin_42182146/article/details/118873865

 

首先来说,spring中的监听机制运用的设计模式为 观察者模式;

那么简易的观察者模式有两个主要角色:

观察者与被观察者;

被观察者主动通知观察者,观察者做出相应的响应;因此,被观察者维护观察者的列表;

 

spring中使用多播器,监听器,事件来完成监听机制;

多播器-ApplicationEventMulticaster,监听器-ApplicationListener,事件-ApplicationEvent

 

 三者的关系类似于:

多播器ApplicationEventMulticaster 维护了一系列监听器ApplicationListener 列表;(这只是个描述,实际上并不是直接维护了一个ApplicationListener列表)。

ApplicationEventMulticaster 发送 事件ApplicationEvent;监听器接收到事件ApplicationEvent之后,做出响应,即调用onApplicationEvent(E event)方法;

 

类比于观察者模式角色,则

观察者:监听器ApplicationListener ,需要自定义一个响应方法体;

被观察者:IOC容器,IOC容器委托ApplicationEventMulticaster发布事件;发布事件的动作就是主动通知观察者的动作。

 

spring中如何简易实现自定义监听机制:

  实现效果:发送‘”饿了事件“,spring响应买零食;发送“”渴了事件“”,spring响应买饮料

 

1,自定义需要监听的事件,extends ApplicationContextEvent

此处自定义了两个事件,

复制代码
public abstract class MyEvent extends ApplicationContextEvent {

    // 事件描述
    private String description;

    public MyEvent(ApplicationContext source, String description) {
        super(source);
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}
复制代码

 

//自定义事件
public class HungryEvent extends MyEvent {

    public HungryEvent(ApplicationContext source, String description) {
        super(source, description);
    }
}

 

复制代码
/**
 * 自定义事件
 */
public class ThirstyEvent extends MyEvent {

    public ThirstyEvent(ApplicationContext source, String description) {
        super(source, description);
    }
}
复制代码

 

2,自定义监听器

  2.1,implements ApplicationListener<Event>,重写 onApplicationEvent 方法;

复制代码
/**
 * 自定义监听器,对事件做出相应
 * 泛型为此监听器的监听类型
 */
@Component
public class MyListener implements ApplicationListener<MyEvent> {


    @Override
    public void onApplicationEvent(MyEvent event) {
        if("hungry".equals(event.getDescription())){
            System.out.println("监听到hungry,买零食");
        }else if("thirsty".equals(event.getDescription())){
            System.out.println("监听到thirsty,买饮料");
        }

    }

}
复制代码

 

  2.2,使用注解 @Component + @EventListener,该方式比较简单灵活;

复制代码
/**
 * @Component + @EventListener 注解,实现自定义监听方法
 * 两个注解都必须有
 */
@Component
public class MyListener_02 {

    /**
     * 参数为监听的事件类型
     * 方法名可以随意,不一定需要固定的方案
     * @param event
     */
    @EventListener
    public void handleMyEvent(MyEvent event){
        System.out.println("监听到 "+event.getDescription());
    }
}
复制代码

 

3,启动spring服务,发送事件;

复制代码
@ComponentScan
public class ListenerTest_01 {

    public static void main(String[] args) {

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ListenerTest_01.class);

        // 发送事件
        ctx.publishEvent(new HungryEvent(ctx,"hungry"));
        ctx.publishEvent(new ThirstyEvent(ctx,"thirsty")); 
  }
}
复制代码

 

运行结果:

监听到hungry,买零食
监听到thirsty,买饮料

 

当一个事件同时使用两种方式设置了监听器,运行结果:

监听到 hungry
监听到hungry,买零食
监听到 thirsty
监听到thirsty,买饮料

 

由此,就是实现了一个最简单的spring监听机制;并且,注解配置的监听器 优于 接口先执行

 

 

上述代码,并没有自定义多播器ApplicationEventMulticaster,也没有显式将监听器ApplicationListener关联ApplicationEventMulticaster,

实际上,如果没有自定义ApplicationEventMulticaster,spring会使用默认的SimpleApplicationEventMulticaster;

通过@Component注解将自定义的监听器交给spring管理之后,spring初始化时会自动将自定义的ApplicationListener加入到多播器的监听器列表中;

 

源码部分:

ApplicationEventMulticaster 是一个接口,可以发现他的功能就是:

1,添加/删除ApplicationListener;

2,发布事件

复制代码
/**
 * Interface to be implemented by objects that can manage a number of
 * {@link ApplicationListener} objects and publish events to them.
 *
 * <p>An {@link org.springframework.context.ApplicationEventPublisher}, typically
 * a Spring {@link org.springframework.context.ApplicationContext}, can use an
 * {@code ApplicationEventMulticaster} as a delegate for actually publishing events.
 */
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 remove
     */
    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 registered.
     */
    void removeAllListeners();

    /**
     * Multicast the given application event to appropriate listeners.
     * <p>Consider using {@link #multicastEvent(ApplicationEvent, ResolvableType)}
     * if possible as it provides 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 {@code null})
     * @since 4.2
     */
    void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);

}
复制代码

 

ApplicationListener也是一个接口,泛型<E extends ApplicationEvent>决定了该监听器监听的事件类型;

他只有一个方法,该方法当监听到事件发生之后执行;

复制代码
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

    /**
     * Handle an application event.
     * @param event the event to respond to
     */
    void onApplicationEvent(E event);

}
复制代码

 

ApplicationContextEvent 为抽象类,自定义事件就会继承该类;

复制代码
public abstract class ApplicationContextEvent extends ApplicationEvent {

    /**
     * Create a new ContextStartedEvent.
     * @param source the {@code ApplicationContext} that the event is raised for
     * (must not be {@code null})
     */
    public ApplicationContextEvent(ApplicationContext source) {
        super(source);
    }

    /**
     * Get the {@code ApplicationContext} that the event was raised for.
     */
    public final ApplicationContext getApplicationContext() {
        return (ApplicationContext) getSource();
    }

}
复制代码

 

spring启动的时候是如何初始化多播器的呢?

以下参考:https://blog.csdn.net/lewismago/article/details/113534310

 

 众所周知,spring初始化的核心方法为:org.springframework.context.support.AbstractApplicationContext#refresh()

复制代码
//org.springframework.context.support.AbstractApplicationContext#refresh
    // 十三个方法调用
    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            
            // 1,准备工作,设置容器的启动时间,设置活跃状态等等,
            // 获取Environment对象加载到Spring环境中,准备监听器和事件的集合对象
            this.prepareRefresh();
            
            // 2,创建容器对象:DefaultListableBeanFactory
            // 加载xml配置文件的bean到该工程,最重要的就是BeanDefinition
            // lorg.springframework.web.context.support.AnnotationConfigWebApplicationContext#loadBeanDefinitions
            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            
            // 3,beanFactory的准备工作,对beanFactory的属性进行填充
            // 设置忽略的依赖等等,addBeanPostProcessor()等等
            // 例如:beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
            this.prepareBeanFactory(beanFactory);

            try {
                // 4,留给子类做扩展的额外方法,一般不做扩展
                this.postProcessBeanFactory(beanFactory);    
                
                // 5,调用BeanFactoryPostProcessor方法,此处可以修改BeanDefinition
                // ???private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();什么情况下add的?
                // BeanDefinitionRegistryPostProcessor !!
                // Invoke factory processors registered as beans in the context.
                // Instantiate and invoke all registered BeanFactoryPostProcessor beans,respecting explicit order if given.
                this.invokeBeanFactoryPostProcessors(beanFactory);
                
                // 6,注册bean处理器,这里只是注册功能,并没有调用
                this.registerBeanPostProcessors(beanFactory);    
                
                // 7,为上下文初始化Message源,即不同语言的消息体国际化处理
                // 主要涉及到 "messageSource", MessageSource.class 的处理
                this.initMessageSource();
                
                // 8,初始化事件监听器多路广播器,一般情况下为默认值
                // this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
                // Initialize event multicaster for this context.
                this.initApplicationEventMulticaster();
                
                // 9,留给子类初始化其他bean
                this.onRefresh();
                
                // 10,在所有注册bean中寻找linstner bean,注册到多播器中
                // Check for listener beans and register them.
                this.registerListeners();
                
                // 11,实例化剩下的非懒加载的单例对象
                // 此实例化操作实际上包含了实例化和初始化整个操作
                // beanFactory.preInstantiateSingletons();
                // 实际会调用的是 >org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
                // 最终会调用.getBean();方法 >org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)
                this.finishBeanFactoryInitialization(beanFactory);
                
                // 12,完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,发送ContextRefreshEvent通知
                // Last step: publish corresponding event.
                this.finishRefresh();
            } catch  (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // 13,
                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            } finally {
                this.resetCommonCaches();
            }

        }
    }
复制代码

 

整个初始化方法,涉及到spring监听机制的步骤大概如下:

1,初始化多播器 initApplicationEventMulticaster()

2,将注册的bean中寻找listener,并将他们关联到多播器中 registerListeners();

3,发布事件 this.finishRefresh();

 

1,初始话多播器:

复制代码
    /**
     * Name of the ApplicationEventMulticaster bean in the factory.
     * If none is supplied, a default SimpleApplicationEventMulticaster is used.
     * @see org.springframework.context.event.ApplicationEventMulticaster
     * @see org.springframework.context.event.SimpleApplicationEventMulticaster
     */
    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
    
    /**
     * Initialize the ApplicationEventMulticaster.
     * Uses SimpleApplicationEventMulticaster if none defined in the context.
     * @see org.springframework.context.event.SimpleApplicationEventMulticaster
     */
    protected void initApplicationEventMulticaster() {
        // 获取当前beanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        // 如果存在自定义的“applicationEventMulticaster”,就使用自定义的多播器
        // beanName一定要使用‘applicationEventMulticaster’
        if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
            this.applicationEventMulticaster =
                    beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
            if (logger.isTraceEnabled()) {
                logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        }
        else {
            // 默认使用SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster
            // Absxxxx 存在private final ListenerRetriever defaultRetriever,里保存了listener的引用
            // this.defaultRetriever.applicationListeners.add(listener);
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            // 将创建好的对象注册进上下文
            beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
            if (logger.isTraceEnabled()) {
                logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
                        "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
            }
        }
    }
    
复制代码

 

2,注册listeners + 发布早期事件;

复制代码
    /**
     * Add beans that implement ApplicationListener as listeners.
     * Doesn't affect other listeners, which can be added without being beans.
     */
    protected void registerListeners() {
        // Register statically specified listeners first.
        // this.applicationListeners的get方法,遍历程序中已经存在的监听器,并将监听器加入到多播器中
        for (ApplicationListener<?> listener : getApplicationListeners()) {
            getApplicationEventMulticaster().addApplicationListener(listener);
        }
        
        // addAddApplicationListener(),addApplicationListenerBean()方法其实调用的
        // org.springframework.context.event.AbstractApplicationEventMulticaster#addApplicationListener
        // 其实AbstractApplicationEventMulticaster并不直接存在applicationListeners属性,而是执行this.defaultRetriever.applicationListeners.add(listener);
        // 该属性为private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);

        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let post-processors apply to them!
        // 从容器中获取所有实现了ApplicationListener接口的bd,并将beaName加入到多播器中;
        // 此时自定义的listener还没有进行实例化
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
        for (String listenerBeanName : listenerBeanNames) {
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        // 发布早期的监听事件集合
        // 在refresh() 第一个方法 prepareRefresh() 中初始化了;
        // Publish early application events now that we finally have a multicaster...
        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }
    }

}
复制代码

 

3,发布事件 ==>重点是publishEvent方法进行了事件发布

该方法最终会调用:org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)

 

复制代码
    /**
     * Finish the refresh of this context, invoking the LifecycleProcessor's
     * onRefresh() method and publishing the
     * {@link org.springframework.context.event.ContextRefreshedEvent}.
     */
    protected void finishRefresh() {
        // Clear context-level resource caches (such as ASM metadata from scanning).
        clearResourceCaches();

        // Initialize lifecycle processor for this context.
        // 为上下文初始化生命周期处理器
        initLifecycleProcessor();

        // Propagate refresh to lifecycle processor first.
        getLifecycleProcessor().onRefresh();

        // Publish the final event.
        // 发布事件,新建ContextRefreshedEvent发布到监听器
        publishEvent(new ContextRefreshedEvent(this));

        // Participate in LiveBeansView MBean, if active.
        LiveBeansView.registerApplicationContext(this);
    }
复制代码

 

复制代码
    /**
     * Publish the given event to all listeners.
     * <p>Note: Listeners get initialized after the MessageSource, to be able
     * to access it within listener implementations. Thus, MessageSource
     * implementations cannot publish events.
     * @param event the event to publish (may be application-specific or a
     * standard framework event)
     */
    @Override
    public void publishEvent(ApplicationEvent event) {
        publishEvent(event, null);
    }

    /**
     * Publish the given event to all listeners.
     * <p>Note: Listeners get initialized after the MessageSource, to be able
     * to access it within listener implementations. Thus, MessageSource
     * implementations cannot publish events.
     * @param event the event to publish (may be an {@link ApplicationEvent}
     * or a payload object to be turned into a {@link PayloadApplicationEvent})
     */
    @Override
    public void publishEvent(Object event) {
        publishEvent(event, null);
    }

    /**
     * Publish the given event to all listeners.
     * @param event the event to publish (may be an {@link ApplicationEvent}
     * or a payload object to be turned into a {@link PayloadApplicationEvent})
     * @param eventType the resolved event type, if known
     * @since 4.2
     */
    protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
        Assert.notNull(event, "Event must not be null");

        // Decorate event as an ApplicationEvent if necessary
        ApplicationEvent applicationEvent;
        if (event instanceof ApplicationEvent) {
            applicationEvent = (ApplicationEvent) event;
        }
        else {
            applicationEvent = new PayloadApplicationEvent<>(this, event);
            if (eventType == null) {
                eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
            }
        }

        // Multicast right now if possible - or lazily once the multicaster is initialized
        if (this.earlyApplicationEvents != null) {
            this.earlyApplicationEvents.add(applicationEvent);
        }
        else {
            getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
        }

        // Publish event via parent context as well...
        if (this.parent != null) {
            if (this.parent instanceof AbstractApplicationContext) {
                ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
            }
            else {
                this.parent.publishEvent(event);
            }
        }
    }
复制代码

 

使用默认方法:

复制代码
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

    @Nullable
    private Executor taskExecutor;

    @Nullable
    private ErrorHandler errorHandler;
    
    // 省略...

    @Override
    public void multicastEvent(ApplicationEvent event) {
        // resolveDefaultEventType会获取event 监听的类型,即该ApplicationEvent的泛型
        multicastEvent(event, resolveDefaultEventType(event));
    }

    @Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        // 异步处理器
        Executor executor = getTaskExecutor();
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            if (executor != null) {
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
                invokeListener(listener, event);
            }
        }
    }
    

    /**
     * Invoke the given listener with the given event.
     * @param listener the ApplicationListener to invoke
     * @param event the current event to propagate
     * @since 4.1
     */
    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        ErrorHandler errorHandler = getErrorHandler();
        if (errorHandler != null) {
            try {
                doInvokeListener(listener, event);
            }
            catch (Throwable err) {
                errorHandler.handleError(err);
            }
        }
        else {
            doInvokeListener(listener, event);
        }
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            // 调用监听器的响应方法
            listener.onApplicationEvent(event);
        }
        catch (ClassCastException ex) {
            String msg = ex.getMessage();
            if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
                // Possibly a lambda-defined listener which we could not resolve the generic event type for
                // -> let's suppress the exception and just log a debug message.
                Log logger = LogFactory.getLog(getClass());
                if (logger.isTraceEnabled()) {
                    logger.trace("Non-matching event type for listener: " + listener, ex);
                }
            }
            else {
                throw ex;
            }
        }
    }

}
复制代码

 

调用链为:

--》publishEvent(new ContextRefreshedEvent(this));

--》getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);

--》invokeListener(listener, event);

--》listener.onApplicationEvent(event);

 

posted @   豆浆不要糖  阅读(498)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
点击右上角即可分享
微信分享提示