什么是监听器-----@EventListener

最近在研究springcloud框架,当我在学习框架的时候,学会用其实并不难,难的是我们要看懂里面的源码,这却需要耗费很多的时间。今天闲来无事,熬夜看看代码吧,哈哈

在学习springcloud的时候,我听到了很多高大上的词汇:Nacos心跳机制、策略模式、事件机制、长轮询。。。等,然后结果网上百度一查,原本指望着有高人的一篇博客就能恍然大悟,但结果都是我太年轻,本来想从入门到精通,到头来经历了几个小时的苦苦挣扎之后终于放弃。但我就是要做逆境人。废话不多说,来看源码。今天我研究的是spring的监听器------@EventListener注解

首先来看一个场景,这里是截取的网上的博客例子:

应用场景类型:
1. 用户注册成功后,此时需要做以下这么多事情:
  1. 加积分
  2. 发确认邮件
  3. 如果时游戏帐户,此时赠送游戏大礼包


耦合性高的解决办法:
  1. 创建一个UserService 并对每一个功能都添加一个方法,这样耦合非常严重,以后增加一个给用户发短信提醒的功能,则可能需要再添加一个Service来进行处理,也不方便后期的维护





低耦合的事件驱动模型的解决方法:
1. 首先时一种对象间的一种一对多的关系;最简单的如交通信号灯,信号灯时目标(相当于用户注册),行人注视着信号灯(相当于加积分,发确认邮件等)。
2. 当信号灯发送对应的颜色(发布),观察者(行人)就可以接受到改变。
3. 观察者时如何进行处理的(如行人如何走,走的快还是慢,目标不会进行管理),目标不需要进行干涉;此时就松耦合了他们之间的关系

这里写图片描述

 直接把链接贴出来,上面有很详细的例子和源码:

​​​​​​Spring中的事件机制之观察者模式_m0_37779570的博客-优快云博客

我贴了一下源码一运行,果然,好神奇!那总结一下我是怎么做到的呢?

第一步:

要在触发连带事件的地方,写上这样一段代码,通常管这样的操作叫做发布任务:

//发布任务
        publisher.publishEvent(new UserCreationEvent(user));

第二步:额。。。好像没有第二步了。。咦?就这样实现了事件机制?但我们看这里用到了一个变量:publicher,这是什么?原来上面自动注入了:

@Autowired
    private ApplicationEventPublisher applicationEventPublisher;

 那我们知道像这种spring容器自带的可以直接使用的类是spring容器自带的,总之spring容器在初始化的时候,自己帮我们给这个变量初始化了,这里就不翻源码了。。。。

而后,后面传了一个参数,类型是UserCreationEvent,这一看就是我自己定义的类,关键它继承了一个类:ApplicationEvent,因为它继承了这个类,所以spring'容器知道了:哦,这是一个事件。

那现在我想,我只需要传这样一个ApplicationEvent事件对象,就行了吗?不可能啊,那spring容器怎么知道这个事件连带的动作是什么呢?那一定在listener中,什么地方用到了这个类名!这个时候我看到,在定义CreationEventListener中,每个方法的参数恰恰就是我自己定义的UserCreationEvent这个类啊。

同时又有一个问题,那spring容器时怎么知道这样一个方法是一个listener呢?答案时我在类上面加了@EventListener这个注解。。。

这时候我们再从头捋一下:首先spring容器在初始化的时候,一定是通过什么手段检测到了我自己定义的这些listener,兵并且给我的publisher初始化了,然后当我调用了publishEvent这个方法的时候,spring底层帮我去调用了这些listener所对应的方法了。

 那最后我再去找一下,到底底层在什么地方去调用了我写的这些listener对应的方法了呢?好神奇促使了我的好奇心,唉。。。

翻了源码最终我找到了这样一个类:ApplicationListenerMethodAdapter

public void processEvent(ApplicationEvent event) {
        Object[] args = this.resolveArguments(event);
        if (this.shouldHandle(event, args)) {
            Object result = this.doInvoke(args);
            if (result != null) {
                this.handleResult(result);
            } else {
                this.logger.trace("No result object given - no result to handle");
            }
        }

    }

 这个方法里调用了doInvoke这个方法,我们点开这个方法之后,终于看到了我熟悉的东西:

@Nullable
    protected Object doInvoke(Object... args) {
        Object bean = this.getTargetBean();
        if (bean.equals((Object)null)) {
            return null;
        } else {
            ReflectionUtils.makeAccessible(this.method);

            try {
                return this.method.invoke(bean, args);
            } catch (IllegalArgumentException var6) {
                this.assertTargetBean(this.method, bean, args);
                throw new IllegalStateException(this.getInvocationErrorMessage(bean, var6.getMessage(), args), var6);
            } catch (IllegalAccessException var7) {
                throw new IllegalStateException(this.getInvocationErrorMessage(bean, var7.getMessage(), args), var7);
            } catch (InvocationTargetException var8) {
                Throwable targetException = var8.getTargetException();
                if (targetException instanceof RuntimeException) {
                    throw (RuntimeException)targetException;
                } else {
                    String msg = this.getInvocationErrorMessage(bean, "Failed to invoke event listener method", args);
                    throw new UndeclaredThrowableException(targetException, msg);
                }
            }
        }
    }

makeAccessible和method.invoke,这不就是强制反射和反射下的方法调用嘛。。

呜呜,顶不住了,睡了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_34116044

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值