最近在研究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,这不就是强制反射和反射下的方法调用嘛。。
呜呜,顶不住了,睡了