Java回调机制在RPC框架中的应用示例
完整源码:
应用场景描述:
服务提供者在项目启动时,创建并启动一个TCP服务器,然后将自己提供的所有服务注册到注册中心。
这里有3个角色:
1.服务提供者
2.TCP服务器
3.注册中心
引出回调:
服务提供者,要求TCP服务器启动成功之后,回调一下"注册服务"的逻辑。
开始撸码:
首先定义一个回调基类,这是一个抽象类,里面只有一个抽象的回调函数,是将来回调时要实现的方法
/**
* 回调基类
*
* @author syj
*/
public abstract class BaseCallBack {
/**
* 回调执行逻辑
*
* @throws Exception
*/
public abstract void run() throws Exception;
}
谁来调用这个回调函数呢,前面说了,TCP服务器启动之后要调用这个回调函数,所以回调的操作要在TCP服务器中完成。
TCP服务器是一个具体的服务实现,我们可能会有多种服务器的实现,所以先定义一个抽象的服务类:
/**
* 服务抽象
*
* @author syj
*/
public abstract class Server { // 服务启动后回调
private BaseCallBack startedCallBack; // 服务停止后回调
private BaseCallBack stopedCallBack; /**
* 设置服务启动后的回调逻辑
*
* @param startedCallBack
*/
public void setStartedCallBack(BaseCallBack startedCallBack) {
this.startedCallBack = startedCallBack;
} /**
* 设置服务停止后的回调逻辑
*
* @param stopedCallBack
*/
public void setStopedCallBack(BaseCallBack stopedCallBack) {
this.stopedCallBack = stopedCallBack;
} /**
* 服务启动后回调
*/
public void onStarted() {
if (startedCallBack != null) {
try {
startedCallBack.run();
} catch (Exception e) {
e.printStackTrace();
}
}
} /**
* 服务停止后回调
*/
public void onStoped() {
if (stopedCallBack != null) {
try {
stopedCallBack.run();
} catch (Exception e) {
e.printStackTrace();
}
}
} /**
* 启动服务
*
* @param provider
* @throws Exception
*/
public abstract void start(Provider provider) throws Exception; /**
* 停止服务
*
* @throws Exception
*/
public abstract void stop() throws Exception; }
这个服务器抽象类,主要有启动服务和停止服务的方法,还持有两个回调对象,一个是服务器启动后的回调对象,一个是服务器停止后的回调对象。并有两个方法分别去调用这两个回调对象的run方法。
下面定义一个TCP服务器类,它是上面服务器抽象类的一个具体实现类:
/**
* 服务实现类
*
* @author syj
*/
public class TcpServerImpl extends Server { /**
* 启动服务
*
* @param provider
*/
@Override
public void start(Provider provider) {
System.out.println(">>>> start! " + provider.getTcpSrvAddr() + ":" + provider.getTcpSrvPort());
// 启动后回调
onStarted(); } /**
* 停止服务
*
*/
@Override
public void stop() {
System.out.println(">>>> stop!");
// 停止后回调
onStoped();
}
}
该类主要有两个功能,一个是启动TCP服务,一个是停止TCP服务,这两个方法的最后都需要触发回调逻辑的执行;
关于具体回调逻辑的定义写在哪里呢?自然是服务的提供者最清楚,所以写在服务提供者类中最合适:
import java.util.TreeSet; /**
* 服务操作
*
* @author syj
*/
public class Provider { // 模拟要注册的服务列表
public static TreeSet<String> serviceKeys = new TreeSet<String>() {{
add("userService");
add("productService");
add("orderService");
}}; // 模拟本机http服务使用的ip和端口
public static String localAddress = "127.0.0.1:8081"; // TCP服务器地址
private String tcpSrvAddr; // TCP服务器端口
private int tcpSrvPort; public String getTcpSrvAddr() {
return tcpSrvAddr;
} public int getTcpSrvPort() {
return tcpSrvPort;
} private Server server;
private Registry registry; public Provider() {
} /**
* 初始化配置
*
* @param tcpSrvAddr
* @param tcpSrvPort
*/
public void initConfig(String tcpSrvAddr, int tcpSrvPort) {
this.tcpSrvAddr = tcpSrvAddr;
this.tcpSrvPort = tcpSrvPort;
} /**
* 启动服务
*/
public void start() {
try {
registry = Registry.class.newInstance();
server = TcpServerImpl.class.newInstance();
// 设置服务启动后回调逻辑
server.setStartedCallBack(new BaseCallBack() {
@Override
public void run() {
System.out.println(">>>> setStartedCallBack:" + serviceKeys + ":" + localAddress);
// 注册服务
registry.start();
registry.registry(serviceKeys, localAddress);
}
}); // 设置服务停止后回调逻辑
server.setStopedCallBack(new BaseCallBack() {
@Override
public void run() {
System.out.println(">>>> setStopedCallBack:" + tcpSrvAddr + ":" + tcpSrvPort);
registry.remove(serviceKeys, localAddress);
}
}); // 启动服务
server.start(this);
} catch (Exception e) {
e.printStackTrace();
}
} /**
* 停止服务
*/
public void stop() {
try {
server.stop();
} catch (Exception e) {
e.printStackTrace();
}
}
}
由于服务提供者需要启动TCP服务器,所以它依赖一个Server对象,在他的start方法中,启动TCP服务之前,先给这个TCP服务设置两个回调回调具体逻辑,就是前面说的一个是TCP服务器启动之后要执行的逻辑,一个是TCP服务器停止之后要执行的逻辑。
TCP服务器启动成功之后,要将服务提供者的所有服务注册到注册中心,TCP服务器停止之后要从注册中心移除自己的所有服务。
下面是注册中心类,它只负责服务的注册和移除,别的事不管:
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet; /**
* 服务注册中心
*
* @author syj
*/
public class Registry { private Map<String, TreeSet<String>> registryData; public void start() {
registryData = new HashMap<String, TreeSet<String>>();
System.out.println(">>>> 注册中心创建成功");
} public void stop() {
registryData.clear();
} public boolean registry(Set<String> keys, String value) {
if (keys==null || keys.size()==0 || value==null || value.trim().length()==0) {
return false;
}
for (String key : keys) {
TreeSet<String> values = registryData.get(key);
if (values == null) {
values = new TreeSet<>();
registryData.put(key, values);
}
values.add(value);
}
System.out.println(">>>> 服务注册成功");
return true;
} public boolean remove(Set<String> keys, String value) {
if (keys==null || keys.size()==0 || value==null || value.trim().length()==0) {
return false;
}
for (String key : keys) {
TreeSet<String> values = registryData.get(key);
if (values != null) {
values.remove(value);
}
}
System.out.println(">>>> 服务移除成功");
return true;
}
}
写个测试类测试一下:
/**
* 测试类
*
* @author syj
*/
public class App {
// TCP 服务器IP
public static String tcpSrvAddr = "192.168.11.23";
// TCP 服务端口
public static int tcpSrvPort = 9090; public static void main(String[] args) {
Provider provider = new Provider();
provider.initConfig(tcpSrvAddr, tcpSrvPort);
provider.start();
provider.stop();
}
}
输出结果:
>>>> start! 192.168.11.23:
>>>> setStartedCallBack:[orderService, productService, userService]:127.0.0.1:
>>>> 注册中心创建成功
>>>> 服务注册成功
>>>> stop!
>>>> setStopedCallBack:192.168.11.23:
>>>> 服务移除成功
总结:
A类调用B类的某个方法,B类的该方法中又调用了A类的某个方法,这就是回调。
这仅是一个形象的描述,具体的回调机制在实际应用时会很灵活。 比如这个例子中,Provider类的start方法调用啦Server类的start方法,而Server类的start方法中又调用了onStarted方法,
虽然这个onStarted方法不是Provider中的方法,但其执行的回调逻辑是在Provider中通过setStartedCallBack()来设置的。
Java回调机制在RPC框架中的应用示例的更多相关文章
- Java实现简单的RPC框架(美团面试)
一.RPC简介 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用) ...
- JDK动态代理在RPC框架中的应用
RPC框架中一般都有3个角色:服务提供者.服务消费者和注册中心.服务提供者将服务注册到注册中心,服务消费者从注册中心拉取服务的地址,并根据服务地址向服务提供者发起RPC调用.动态代理在这个RPC调用的 ...
- java回调机制及其实现(转)
1. 什么是回调函数 回调函数,顾名思义,用于回调的函数.回调函数只是一个功能片段,由用户按照回调函数调用约定来实现的一个函数.回调函数是一个工作流的一部分,由工作流来决定函数的调用(回调)时机.回调 ...
- Java回调机制总结
调用和回调机制 在一个应用系统中, 无论使用何种语言开发, 必然存在模块之间的调用, 调用的方式分为几种: 1.同步调用 同步调用是最基本并且最简单的一种调用方式, 类A的方法a()调用类B的方法b( ...
- 转:一个经典例子让你彻彻底底理解java回调机制
一个经典例子让你彻彻底底理解java回调机制 转帖请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/17483273 ...
- Java实现简单的RPC框架
一.RPC简介 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用) ...
- Java 实现简单的RPC框架
0 引言 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用).He ...
- JAVA回调机制(CallBack)详解
序言 最近学习java,接触到了回调机制(CallBack).初识时感觉比较混乱,而且在网上搜索到的相关的讲解,要么一言带过,要么说的比较单纯的像是给CallBack做了一个定义.当然了,我在理解了回 ...
- JAVA回调机制解析
一.回调机制概述 回调机制在JAVA代码中一直遇到,但之前不懂其原理,几乎都是绕着走.俗话说做不愿意做的事情叫做突破,故诞生了该文章,算是新年的新气象,新突破! 回调机制是什么?其实回 ...
随机推荐
- S3cmd
一:安装方法 #wget http://nchc.dl.sourceforge.net/project/s3tools/s3cmd/1.0.0/s3cmd-1.0.0.tar.gz #tar -zxf ...
- docker 基本常用操作做
docker 基本常用操作做(只列举入门常用的命令) 容器生命周期管理 docker run :创建一个新的容器并运行一个命令 -a stdin: 指定标准输入输出内容类型,可选 STDIN/STDO ...
- k8s删除pod时,docker服务出现挂载点泄漏问题的解决
k8s更新版本后,老的POD一直出现Terminating,多久都不能删除. 然后,进入具体的节点机器之后,查看日志输出如下类似: ERROR: driver "overlay" ...
- 简单理解和使用 C# 委托与事件
委托和事件 委托:委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程 ...
- P1559 运动员最佳匹配问题[最大费用最大流]
题目描述 羽毛球队有男女运动员各n人.给定2 个n×n矩阵P和Q.P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势:Q[i][j]是女运动员i和男运动员j配合的女运动员竞赛优势 ...
- LG2664 树上游戏
树上游戏 题目描述 lrb有一棵树,树的每个节点有个颜色.给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量.以及 $$sum_i=\sum_{j=1}^ns(i,j)$$ 现在他想让 ...
- 什么情况下使用large training data会非常有效
收集大量的数据可能比算法的优劣更重要 Banko和Brill在2001年做了一个研究,是关于在句子中对易混单词进行识别,画出了上图的右边的那个图,这个图显示了对于不同的算法,它们的表现相似,但是随着t ...
- Fzu-html1
Fzu-趣考网-前端1 html 题目: 使用html写出h1~h6六种格式的hello world 使用html的table标签制作一个表格,存储本学期专业课程(参考教务处课表) 使用html的sc ...
- 【爬虫】把抓到数据存起来——爬虫绝配mongodb
[爬虫]把抓到数据存起来——爬虫绝配mongodb 视频地址 抓取数据的方法,前面的课程该讲的都已经讲了,爬取下来数据只是第一步,第二步就是要先存起来.我们最容易想到的就是存文件里喽,python写文 ...
- Kubernetes 学习10 Service资源
一.Service对应组件关系 1.在kubernetes平台之上,pod是有生命周期的,所以为了能够给对应的客户端提供一个固定的访问端点,因此我们在客户端和服务Pod之间添加一个固定的中间层,这个中 ...