居然可以这样监听
前几天的文章大家说太“短”了,今天你们再看看……
《进阶实战:从零开始撸一个 RPC 框架》专栏更新进展:
【前言】
【理论篇】
揭开神秘的面纱:什么是微服务框架? 揭开神秘的面纱:主流微服务框架架构设计 注册发现:什么是注册发现? 注册发现:Nacos 服务注册发现c 注册发现:使用 Zookeeper 实现注册发现 动态代理:动态代理基本介绍,常见代理技术对比 序列化:序列化介绍 序列化:常见序列化技术对比 网络通信:BIO 和 NIO 网络通信:认识 Netty 框架 网络通信:小白都能看得懂的 TCP粘包拆包
【实战篇】
前面讲到要使自定义注解生效需要写一段驱动代码,那驱动代码什么开始执行比较合适呢?大家可能知道答案:应用启动的时候。
回到具体的代码实现中,假设应用程序(客户端或服务端)依赖了 RPC框架并且使用了Spring
环境,对Spring
比较熟悉的小伙伴应该知道,Spring
在启动的过程中会初始化bean
,那是不是可以在初始化bean
之后去执行这段驱动代码呢?答案是肯定的。
查阅相关资料后,Spring 监听器可以实现上面这个诉求。
Spring 监听器
监听器在使用过程中可以监听某些感兴趣的事件,监听到事件来临时可以做出响应处理。
Spring事件监听体系包括三大核心组件:事件监听器、事件、事件广播器,如下图:
事件广播器
事件广播器或者叫事件多播器负责广播发生的事件并通知所有监听器,所有的事件监听器都会提前注册在事件广播器中。
事件
所有的动作都可能被定义为一个事件,事件发生后事件广播器通知所有的监听器,监听器根据情况做出响应。
Spring 定义了一个事件基类:ApplicationEvent
,看一下源码:
public abstract class ApplicationEvent extends EventObject {
/** 事件发生的时间 */
private final long timestamp;
/**
* 创建一个实例
* @param source 事件来源
*/
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
……省略其他代码
}
ApplicationEvent
继承 JDK 定义的事件基类:EventObject
,
public class EventObject implements java.io.Serializable {
/**
* The object on which the Event initially occurred.
*/
protected transient Object source;
……省略其他代码
}
ApplicationEvent
是一个抽象类,如果需要自定义事件需要继承这个类:
public class MyEvent extends ApplicationEvent {
……省略其他代码
}
当然 Spring 自身已经定义了非常多的事件:
ContextRefreshedEvent:ApplicationContext 被初始化或刷新时,该事件被发布。初始化是指所有的Bean被成功装载,后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用。
ContextStartedEvent:ApplicationContext 启动后,该事件被发布。
ContextStoppedEvent:ApplicationContext 停止后,该事件被发布。
ContextClosedEvent:ApplicationContext 关闭后,该事件被发布。
以上仅仅列举了几个常用的 Spring 事件。
根据前面分析的业务诉求,我们期望所有的bean
初始化完之后开始执行自定义注解的驱动代码,所以ContextRefreshedEvent
这个事件才是我们感兴趣的,看一下源码:
public class ContextRefreshedEvent extends ApplicationContextEvent {
public ContextRefreshedEvent(ApplicationContext source) {
super(source);
}
}
看起来非常简单,继承了ApplicationContextEvent
,继续跟一下源码可以发现ApplicationContextEvent
继承了我们上面讲的ApplicationEvent
。
事件监听器
所有的事件监听器都注册在事件广播器中,这好比观察者模式中的观察者。
在 Spring 中ApplicationListener
是事件监听器的顶层接口,继承自 JDK 的EventListener
,所有的监听器都必须实现这个接口。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* 处理事件
* @param event 待响应的事件
*/
void onApplicationEvent(E event);
// ……省略其他代码
}
定义了一个onApplicationEvent
方法,当有感兴趣的事件发生后就会执行这个方法进行处理。
实现自定义监听器
上面介绍了 Spring 监听体系的一些基础知识,并通过一些源码进行辅助介绍,这些代码都不是 RPC 框架要写的,RPC 框架当前要做的是实现一个自定义监听器监听感兴趣的事件。
通过结合业务诉求分析出:自定义一个监听器用来监听 Spring 内置ContextRefreshedEvent
事件。
public class DefaultRpcListener implements ApplicationListener<ContextRefreshedEvent> {
public DefaultRpcListener() {
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// TODO 实现业务逻辑
// 1 服务端逻辑处理
// 2 客户端逻辑处理
}
}
自定义的监听器实现了ApplicationListener
接口,并重写onApplicationEvent
方法,方法中待实现的业务逻辑是重中之重。
待实现的业务逻辑中需要对@ServiceExpose
和@ServiceReference
这两个注解进行处理,@ServiceExpose
对应服务端,@ServiceReference
对应客户端,所以基本就是两大块:服务端逻辑处理和客户端逻辑处理。
注意一下,文中提到的服务端或客户端是站在功能角度上看的,不能片面理解,一个应用程序(服务或微服务)既可能是服务端也可能是客户端:
如上图,微服务 A 调用微服务 B,微服务 B 又调用微服务 C,微服务 B 在整个调用链中既是客户端又是服务端。
代码结构
自定义监听器DefaultRpcListener
放在 listener 包下,目前 RPC 框架代码工程结构如下:
├── easy-rpc-spring-boot-starter
├── pom.xml
├── src
│ └── main
│ ├── java
│ │ └── com
│ │ └── leixiaoshuai
│ │ └── easyrpc
│ │ ├── annotation
│ │ │ ├── ServiceExpose.java
│ │ │ └── ServiceReference.java
│ │ └── listener
│ │ └── DefaultRpcListener.java
│ └── resources
└── target
小结
本小节首先学习了Spring 监听的基本机制,了解到监听体系有三大关键要素:事件监听器、事件、事件广播器,事件监听器会提前注册到事件广播器中,当感兴趣的事件发生后事件广播器会通知到事件监听器,这样事件监听器就可以根据业务场景进行响应。
Spring 提供了事件的基类,大家可以自定义事件,当然也可以直接使用 Spring 内置的事件,结合 RPC 框架的业务特点我们发现ContextRefreshedEvent
事件比较符合我们的诉求。
Spring 定义了事件监听器ApplicationListener
顶层接口,我们只需要实现该接口就可以自定义一个监听器,在监听器中重写onApplicationEvent
方法实现相应的业务逻辑。
自定义监听器主要的业务逻辑包括两大块:服务端和客户端,服务端逻辑主要处理@ServiceExpose
注解,客户端逻辑主要处理@ServiceReferece
注解。关于注解处理的逻辑我们下一小节详细讲解。
-- END --
请珍惜每一个熬夜写技术文章的博主,因为你们再不给三连他们可能没有动力继续更新了😄 欢迎转发给其他需要的人