相关推荐recommended
【spring】 ApplicationListener的使用及原理简析
作者:mmseoamin日期:2024-04-29

文章目录

  • 使用示例:
  • 原理简析:

    前言:ApplicationListener 是spring提供的一个监听器,它可以实现一个简单的发布-订阅功能,用有点外行但最简单通俗的话来解释:监听到主业务在执行到了某个节点之后,在监听器里面做出相应的其它业务变更。下面我们具体看段代码,则能很快的理解:

    再次推荐博主原创idea插件: Equals Inspection , 如果经常使用Objects.equals方法,相信这个插件可以有所帮助

    (欢迎各位前往idea插件marketplace免费下载)

    【spring】 ApplicationListener的使用及原理简析,在这里插入图片描述,第1张

    使用示例:

    java代码:

    首先定义一个业务实体类,实体类定义字段、get set方法、构造函数

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    /**
     * 模拟业务对象实体类
     * @author csdn:孟秋与你
     */
    public class MyBizEntity {
        private String name;
        private Integer age;
    }
    

    再定义一个事件,事件继承ApplicationEvent

    import org.springframework.context.ApplicationEvent;
    /**
     * 自定义事件(继承ApplicationEvent)
     * @author csdn:孟秋与你
     */
    public class MyEvent extends ApplicationEvent {
        public MyEvent(Object source) {
            super(source);
        }
        public MyEvent() {
            // java基础:如果父类只有有参构造 子类需要使用其它构造函数 必须在构造函数第一行调用super 因为子类也是调用父类的构造函数
            super(null);
            // do other
        }
    }
    

    定义一个监听器,实现ApplicationListener接口:

    import org.springframework.context.ApplicationEvent;
    import org.springframework.context.ApplicationListener;
    import org.springframework.stereotype.Component;
    /**
     * 监听事件
     */
    @Component
    public class MyApplicationListener implements ApplicationListener {
        @Override
        public void onApplicationEvent(ApplicationEvent applicationEvent) {
            // 必须判断自己要的类型  因为会监听到所有继承ApplicationEvent的事件
            if (applicationEvent instanceof MyEvent) {
                Object source = applicationEvent.getSource();
                MyBizEntity bizEntity = (MyBizEntity) source;
                System.out.println(bizEntity.getName() + ":------------name");
            }
        }
    }
    

    写一个接口进行测试, 此时监听器就能打印输出了

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    @RequestMapping("/test/listener")
    @RestController
    public class MainBizController {
        @Autowired
        private ApplicationContext context;
        @GetMapping
        public String test() {
            // do something
            
            // 模拟要传递的业务对象
            MyBizEntity bizEntity = new MyBizEntity("name",18);
            MyEvent event = new MyEvent(bizEntity);
            // 上下文 发布事件
            context.publishEvent(event);
            return "success";
        }
    }
    

    原理简析:

    为什么发布了事件,监听器就能够监听到呢? 其实原理很简单,就是spring进行了一个朴实无华的直接调用, 我们来看看源码:

    context.publishEvent默认是调用AbstractApplicationContext类的publishEvent方法,而publishEvent方法里面调用了SimpleApplicationEventMulticaster 类的multicastEvent方法。

    tips: 为什么上下文有publishEvent方法 ?

    因为ApplicationContext继承了ApplicationEventPublisher

    【spring】 ApplicationListener的使用及原理简析,在这里插入图片描述,第2张

    SimpleApplicationEventMulticaster: 首先会获取所有实现了ApplicationListener的监听器 (get by type就可以获取到), 接着会执行 invokeListener方法

    【spring】 ApplicationListener的使用及原理简析,在这里插入图片描述,第3张

    我们看看最后doInvokeListener 做了什么:

    【spring】 ApplicationListener的使用及原理简析,在这里插入图片描述,第4张

    通过上面源码链路,我们不难发现 其实就是调用了publishEvent方法后,spring在我们不轻易能看到的地方 去调用了一下监听器的onApplicationEvent 方法而已,通过源码我们也可以看到 默认是同步调用(没有定义taskExecutor时), 本质上是一个解耦,把原本可能要写在一起的业务代码拆分了。