• Spring监听器---ApplicationListener


    说到事件监听,想到的肯定是观察者模式。但是这儿主要说下spring中的监听是怎么样的流程。

    这就不得不说到spring容器的refresh方法,容器启动过程中,listener相关的主要是这个三个方法:initApplicationEventMulticaster方法初始化事件多播器,后续的事件发布都是由多播器来发布的;registerListeners注册监听器到前面初始化好的多播器上面去;

    finishRefresh容器启动完成最后刷新,发布ContextRefreshedEvent事件。

    1.初始化多播器:获取bean工厂对象ConfigurableListableBeanFactory,判断容器中是否有applicationEventMulticaster多播器,如果没有则创建一个一个简单事件多播器SimpleApplicationEventMulticaster并注册到容器中,后续使用

    2.注册监听器到多播器上并发布早期事件:首先获取容器中已有的监听器(成品对象,从第一张图中可以看到我们自己的组件对象在registerListeners方法调用的时候 还没有初始化,是在下面的finishBeanFactoryInitialization方法中才进行初始化的),注册到多播器;然后获取bean定义中的监听器,也就是我们自己定义的监听器;同样也注册到多播器上去;最后如果有早期事件就去发布早期事件(multicastEvent方法),这些事件只能由已经实例化的监听器监听,我们自己的监听器初始化是在finishBeanFactoryInitialization方法中。

     

    发布事件:multicastEvent方法----->invokeListener方法---->doInvokeListener方法调用监听器的onApplicationEvent

    可以看到这里支持异步发送,但是从上面我们初始化简单多播器的时候,executer对象并没有赋值,因此始终是同步发布。如果我们想实现异步发布事件,那么就要让上面初始化多播器的逻辑走进第一个分支。我们可以在容器中自己继承SimpleApplicationEventMulticaster,并初始化一个线程池,然后将其注册到容器中,bean的名字必须使用“applicationEventMulticaster”,因为此时容器还没有创建真正的对象,只有这个名字的bean定义才会马上去创建对象。这样就可以实现异步发布事件了。

    3.执行finishRefresh方法发布ContextRefreshedEvent事件,标志的容器已经启动完成。

    监听器的流程完了,我们现在来看下使用

    首先实现一个自己的监听器

    package com.nijunyang.spring.listener;
    
            import org.springframework.context.ApplicationEvent;
            import org.springframework.context.ApplicationListener;
            import org.springframework.stereotype.Component;
    
    /**
     * Description:
     * Created by nijunyang on 2020/2/20 21:53
     */
    @Component
    public class MyListener implements ApplicationListener<ApplicationEvent> {
        @Override
        public void onApplicationEvent(ApplicationEvent event) {
            System.out.println("收到事件:" + event.toString());
        }
    }

    新建一个自己的事件:

    package com.nijunyang.spring.listener;
    
    import org.springframework.context.ApplicationEvent;
    
    /**
     * Description:
     * Created by nijunyang on 2020/2/20 22:05
     */
    public class MyApplicationEvent extends ApplicationEvent {
        /**
         * Create a new ApplicationEvent.
         *
         * @param source the object on which the event initially occurred (never {@code null})
         */
        public MyApplicationEvent(Object source) {
            super(source);
        }
    }

    配置类:指定要扫描的包

    package com.nijunyang.spring;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * @author: create by nijunyang
     * @date:2019/10/6
     */
    @Configuration
    @ComponentScan(basePackages = "com.nijunyang.spring.*")
    public class MainConfig {
    }

    测试代码:在容器创建完之后发布自己的事件。

    package com.nijunyang.spring;
    
    import com.nijunyang.spring.listener.MyApplicationEvent;
    import com.nijunyang.spring.model.Student;
    import org.springframework.boot.SpringApplication;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Application {
    
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
            context.publishEvent(new MyApplicationEvent("想涨工资"));
        }
    
    }

    执行代码会发现我们的监听器会监听到两个事件,因为我们监听器监听的事件是ApplicationEvent,上面说到容器启动的时候,最后会执行finishRefresh方法发布ContextRefreshedEvent事件,容器启动完成之后,我们自己手动发布了一个我们自己的事件,因此会监听到两个事件。

     修改我们的监听器,只监听我们自己的事件:

    package com.nijunyang.spring.listener;
    
    import org.springframework.context.ApplicationListener;
    import org.springframework.stereotype.Component;
    
    /**
     * Description:
     * Created by nijunyang on 2020/2/20 21:53
     */
    @Component
    public class MyListener implements ApplicationListener<MyApplicationEvent> {
        @Override
        public void onApplicationEvent(MyApplicationEvent event) {
            System.out.println("收到事件:" + event.toString());
        }
    }

     再次执行代码,发现现在就只能监听我们自己的事件了

    通过spring的监听器,我们不仅可以实现自己相关的业务,还可以通过这个机制将我们自己的组件和spring进行整合,比如阿里的nacos就是通过ApplicationListener与spring整合的;

    springboot和spring中的一些事件:

    ContextClosedEvent:容器关闭的时候,我们可以监听这个事件在容器关闭的时候去清理一些缓存(比如redis)的数据

    ApplicationFailedEvent:该事件为spring boot启动失败时的操作

    ApplicationPreparedEvent:上下文context准备时触发

    ApplicationReadyEvent:上下文已经准备完毕的时候触发,做权限认证的时候。在这个时候就可以去初始化一些权限数据。或者预备其他数据

    ApplicationEnvironmentPreparedEvent:环境事先准备

  • 相关阅读:
    LIKE谓词
    [C#网络编程系列]专题一:网络协议简介
    (zz)Sql Server 2005中的架构(Schema)、用户(User)、角色(Role)和登录(Login)(三)
    zz让你成功的九个心理定律
    zz给 VSTO 插件、文档传送参数
    重构笔记
    (zz)Sql Server 2005中的架构(Schema)、用户(User)、角色(Role)和登录(Login)(二)
    zzVSTO 先瘦身再发布:客户端配置文件
    zz将 VSTO 插件部署给所有用户
    (zz)Sql Server 2005中的架构(Schema)、用户(User)、角色(Role)和登录(Login)(一)
  • 原文地址:https://www.cnblogs.com/nijunyang/p/12339757.html
Copyright © 2020-2023  润新知