一,服务提供者

工程为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. ubuntu最近升级到最新的linux内核后,网络无法使用怎么办?

    答:进入旧的内核中编译需要的网卡模块 1. 启动旧的内核进入系统 2. 安装新内核源码 3. 找出当前的网卡型号 4. 尝试卸载某个与网卡相关的内核模块,观察是否影响当前网卡的使用,如果有影响,那么便 ...

  2. C++学习 之 初识命名空间

    声明:            本人自学C++, 没有计算机基础,在学习的过程难免会出现理解错误,出现风马牛不相及的现象,甚至有可能会贻笑大方. 如果有幸C++大牛能够扫到本人的博客,诚心希望大牛能给予 ...

  3. 使用Statement执行DML和DQL语句

    import com.loaderman.util.JdbcUtil; import java.sql.Connection; import java.sql.DriverManager; impor ...

  4. OpenStack 虚拟机启动流程 UML 分析(内含 UML 源码)

    目录 文章目录 目录 前言 API 请求 Nova API 阶段 Nova Conductor 阶段 Nova Scheduler 阶段 Nova Compute 阶段(计算节点资源分配部分) Nov ...

  5. 阶段3 3.SpringMVC·_03.SpringMVC常用注解_7 ModelAttribute注解

    这个注解可以作用在方法上,也可以作用在参数上 演示 user里面有三个属性, 表单只提交了两个属性.缺少了date属性 date没有获取到值因为也没提交这个值. 下面返回的user对象.上面就会拿到 ...

  6. python 类中__init__函数的使用

    class F: def __init__(self): print('hello china') __init__ 是构造函数,初始化类,每当调用类的时候,就会自动执行这个函数 比如:执行 F() ...

  7. ABAP Field+offset字符串截取

    *删除字符串末尾的字符 DATA:str TYPE string VALUE 'abc,defg,', sub_str TYPE string, num TYPE i. WRITE:/ str. nu ...

  8. CentOS(Oracle_Linux)系统网卡配置文件参数详解

    Each physical and virtual network device on an Oracle Linux system has an associated configuration f ...

  9. flannel下k8s pod及容器无法跨主机互通问题

    参照文档    https://blog.csdn.net/a610786189/article/details/80340556 https://blog.csdn.net/weixin_43092 ...

  10. linux中为什么删除文件比创建文件要快,读取文件和删除文件的过程是什么?

    一.为什么删除文件比创建文件要快? 因为删除文件只是将bitmap位图表中将文件所占据的inode 和dacablock的使用状态从1变成0,相当于释放了这些快的使用权. 二.读取文件和删除文件的过程 ...