一,服务提供者

工程为battercake-provider,项目结构图如下图所示

1.1 先创建一个“卖煎饼”微服务的接口和实现类

package com.jp.service;

public interface BatterCakeService {
/**
* 卖煎饼的服务
*/
public String sellBatterCake(String name);
}
package com.jp.service;

import com.jp.service.BatterCakeService;

/**
* 卖煎饼服务的实现类
*
*/
public class BatterCakeServiceImpl implements BatterCakeService { public String sellBatterCake(String name) {
return name+"煎饼,卖的特别好";
}
}

1.2 RPC框架调用部分

该部分有两个关键部分:RPC服务提供器线程处理类

1)RPC服务提供器

  1. 需要发布的服务存储在一个内存变量serviceList中。(该例就是把卖煎饼服务的实例对象传入
  2. 启动socket,server.accept()方法阻塞在那,监听输入
  3. 针对每一个请求,单独启动一个线程处理
 package com.jp.rpc;

 import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* RPC服务提供器
* 1,将需要发布的服务存储在一个内存变量serviceList中
* 2,启动socket,server.accept()方法阻塞在那,监听输入
* 3,针对每一个请求,单独启动一个线程处理
*/
public class RpcProvider { //存储注册的服务列表
private static List<Object> serviceList; /**
* 发布rpc服务
* @param object 提供(卖煎饼)服务的实例对象
* @param port 监听的端口
* @throws Exception
*/
public static void export(int port,Object... services) throws Exception {
serviceList=Arrays.asList(services);
ServerSocket server = new ServerSocket(port);
Socket client = null;
while (true) {
//阻塞等待输入,每来一个请求就会产生一个socket对象
client = server.accept();
//每一个请求,启动一个线程处理
new Thread(new ServerThread(client,serviceList)).start();
}
}
}

2)线程处理类

ServerThread(socke对象服务实例列表)线程处理类的代码,ServerThread主要做以下几个步骤

  1. 读取客户端发送的服务名
  2. 判断服务是否发布
  3. 如果发布,则走反射逻辑,动态调用,返回结果
  4. 如果未发布,则返回提示通知
 package com.jp.rpc;

 import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.List; public class ServerThread implements Runnable { private Socket client = null; private List<Object> serviceList = null; public ServerThread(Socket client, List<Object> service) {
this.client = client;
this.serviceList = service;
} //@Override
public void run() {
ObjectInputStream input = null;
ObjectOutputStream output = null;
try {
input = new ObjectInputStream(client.getInputStream());
output = new ObjectOutputStream(client.getOutputStream());
// 读取客户端要访问那个service
Class serviceClass = (Class) input.readObject();
// 找到该服务类实例
Object obj = findService(serviceClass);
if (obj == null) {
output.writeObject(serviceClass.getName() + "服务未发现");
} else {
//利用反射调用该方法,返回结果
//从请求中得到请求的方法名和方法参数;加上上面得到了服务对象实例;反射得到具体的方法实例;invoke执行
try {
String methodName = input.readUTF();
Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
Object[] arguments = (Object[]) input.readObject(); Method method = obj.getClass().getMethod(methodName, parameterTypes);
Object result = method.invoke(obj, arguments);
output.writeObject(result);
} catch (Throwable t) {
output.writeObject(t);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
client.close();
input.close();
output.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} } //到服务列表中找服务实例
private Object findService(Class serviceClass) {
for (Object obj : serviceList) {
boolean isFather = serviceClass.isAssignableFrom(obj.getClass());
if (isFather) {
return obj;
}
}
return null;
} }

1.3 发布服务

 package com.jp.start;

 import com.jp.rpc.RpcProvider;
import com.jp.service.BatterCakeService;
import com.jp.service.BatterCakeServiceImpl; public class RpcBootStrap {
public static void main(String[] args) throws Exception {
//实例化“卖煎饼”这个服务的实现类
BatterCakeService batterCakeService =new BatterCakeServiceImpl();
//发布卖煎饼的服务:注册在20006端口,并把提供服务的实例传入
RpcProvider.export(20006,batterCakeService);
}
}

二,服务消费者

消费者工程为battercake-consumer,项目结构图如下图所示

2.1 rpc调用部分

分为两部分:代理类处理器(代理类工厂)和 service的代理类对象(即前面工厂生产返回的)

1)代理类处理器(代理类工厂)

负责生产代理类(传入服务的名字(类?);ip;端口

 package com.jp.rpc;

 import java.lang.reflect.Proxy;

 /**
* 用于生产服务代理类
*/
public class RpcConsumer {
public static <T> T getService(Class<T> clazz,String ip,int port) {
ProxyHandler proxyHandler =new ProxyHandler(ip,port);
return (T)Proxy.newProxyInstance(RpcConsumer.class.getClassLoader(), new Class<?>[] {clazz}, proxyHandler);
}
}

2)服务代理类的处理器(该类就是代理类功能的具体实现者,其实就是封装了调用远程服务的过程(封装请求数据发给远端服务提供者,把提供者返回的结果返回)

  1. 建立socket连接
  2. 封装请求数据,发送给服务提供者
  3. 返回结果
 package com.jp.rpc;

 import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.net.Socket; public class ProxyHandler implements InvocationHandler { private String ip;
private int port; public ProxyHandler(String ip, int port) {
this.ip = ip;
this.port = port;
} //@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket socket = new Socket(this.ip, this.port);
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
try {
output.writeObject(proxy.getClass().getInterfaces()[0]);
output.writeUTF(method.getName());
output.writeObject(method.getParameterTypes());
output.writeObject(args);
output.flush();
Object result = input.readObject();
if (result instanceof Throwable) {
throw (Throwable) result;
}
return result;
} finally {
socket.shutdownOutput();
}
} }

2.2 接下来建立一个测试类RpcTest如下

(跑该测试类前,记得运行在battercake-provider端的RpcBootstrap类发布BatterCakeService服务)

 package com.jp.start;

 import com.jp.rpc.RpcConsumer;
import com.jp.service.BatterCakeService; public class RpcTest {
public static void main(String[] args) {
//生成代理类,三个参数:被代理对象,ip,端口
BatterCakeService batterCakeService = RpcConsumer.getService(BatterCakeService.class, "127.0.0.1", 20006);
//调用代理类的方法并获得结果
String result = batterCakeService.sellBatterCake("双蛋");
System.out.println(result);
}
}

输出结果如下

https://blog.csdn.net/wangyunpeng0319/article/details/78651998

https://www.cnblogs.com/rjzheng/category/1205773.html

java实现RPC的更多相关文章

  1. 【Other】最近在研究的, Java/Springboot/RPC/JPA等

    我的Springboot框架,欢迎关注: https://github.com/junneyang/common-web-starter Dubbo-大波-服务化框架 dubbo_百度搜索 Dubbo ...

  2. 利用jmeter+JAVA对RPC的单接口(dubbo接口等)进行性能测试

    建立JAVA项目 建立maven项目,加入Jmeter所需要的JAR包依赖. POM.xml  加入如下: <dependency> <groupId>org.apache.j ...

  3. java之rpc/orm

    Netty线程模型 其中ChannelPiepline的设计模型采用的是Handler组成的责任链模型 blocking I/O 阻塞nonblocking I/O 非阻塞I/O multiplexi ...

  4. Java讲解RPC的基本实现

    RPC远程过程调用可以说是分布式系统的基础,本文将通过Java演示一次普通的rpc调用到底发生了什么. 我曾经在网上看到有人提问,为什么RPC要叫作远程过程调用,而不叫作RMC远程方法调用.个人认为R ...

  5. 简单的RPC java实现

    RPC的名声大噪之时是在2003年,那一个“冲击波”病毒(Blaster Worm virus)袭卷全球的一年.而“冲击波”正是用着RPC这把刀来敲开了远程电脑的大门.当然RPC 有更多正面的应用,比 ...

  6. Java程序员的现代RPC指南

    Java程序员的现代RPC指南 1.前言 1.1 RPC框架简介 最早接触RPC还是初学Java时,直接用Socket API传东西好麻烦.于是发现了JDK直接支持的RMI,然后就用得不亦乐乎,各种大 ...

  7. Java RMI与RPC的区别

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6542811.html  一:RPC 远程过程调用 RPC(Remote Procedure Call Prot ...

  8. Java实现简单的RPC框架

    一.RPC简介 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用) ...

  9. Java实现简单的RPC框架(美团面试)

    一.RPC简介 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用) ...

随机推荐

  1. koa2环境搭建

    npm install -g koa-generator koa2 ssy-koa2 cd ssy-koa2 npm install

  2. 发布nuget包

    首先在nuget(www.nuget.org)注册账号,这里可以使用微软账号直接登录 一般有两种方式 1:在工程上右键打包然后直接在网站上上传就可以 2:通过获取key,然后使用控制台提交 登录后在右 ...

  3. SqlServer Where后面Case When的使用实例

    SqlServer一个(用户表:a)中有两个字段都是用户ID 第一个ID是(收费员:id_remitter) 第二个ID是(退费员:id_returner) (收费表:b) 如何根据是否退费(F_RE ...

  4. golang(09) golang 接口内部实现

    原文链接 http://www.limerence2017.com/2019/09/24/golang14/#more 前文介绍过golang interface用法,本文详细剖析interface内 ...

  5. Can not find connection pool config file

    暂时未解决 checkActivation=====================true Can Not Parse ConnectionCfg! 2019/10/12-11:23:38 > ...

  6. Java ——关键字 数据类型 变量 常量

    本节重点思维导图 Java程序结构 public class 类名 { public static void main(String[] args){ //……语句 } } 一门语言是由以下各种元素组 ...

  7. python网络应用篇

    正则表达式 import re #引入正则表达式模块  使用re.match/search函数进行匹配(区别:match只匹配字符串的开始,如果不符合正则表达式,则匹配失败,返回None,而searc ...

  8. jump用户管理命令

    ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa手动拷贝id_rsa.pub的内容到其他机器 或者用 ssh-copy,但你得知道对方root密码 ssh-copy-i ...

  9. 【基本优化实践】【1.1】IO优化——把文件迁移到不同物理磁盘

    [1]概念 把不同数据文件移动到不同的物理磁盘,无疑是一个提高IO的有效办法 在资源可以的情况下,尽量把 temp .数据库的主数据文件(mdf).数据库的从数据数据(ndf).数据库的事务日志文件( ...

  10. CF 148D Bag of mice 题解

    题面 这是我做的第一道概率DP题: 做完后发现没有后效性的DP是真的水: 在这里说主要是再捋顺一下思路: 设f[i][j]表示有i只白鼠,j只黑鼠是获胜的概率: 显然:f[i][0]=1; 然后分四种 ...