前言:微服务之间怎么通过socket完成通信;本文通过demo 展示微服务如何通过socket 完成服务之间的通信;
1 使用maven新建两个springboot 服务:模拟实现订单通过订单号获取商品信息:
1.1 创建建springboot 项目后,创建对外提供服务端的api maven模块:
定义通过订单号获取商品信息的接口类:
package org.example.service;
public interface ShopService {
// 返回商品信息
String getOneShop(String shopId);
}
1.2 定义可以反射调用最终实现getOneShop所需要的类:
package org.example.service;
import java.io.Serializable;
public class RpcRequest implements Serializable {
// 方法所在的类
private String className;
// 方法名称
private String methodName;
// 参数类型
private Class[] types;
// 参数值
private Object[] args;
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Class[] getTypes() {
return types;
}
public void setTypes(Class[] types) {
this.types = types;
}
public Object[] getArgs() {
return args;
}
public void setArgs(Object[] args) {
this.args = args;
}
}
1.3 在商品模块maven pom 增加api 模块的依赖项;
1.4 在商品模块实现ShopService 接口:
package com.example.springcloudshopservice.shop;
import org.example.service.ShopService;
public class ShopServiceImpl implements ShopService {
@Override
public String getOneShop(String shopId) {
return "苹果";
}
}
1.5 要想被订单服务调用到该方法,需要对外发布该服务:
package com.example.springcloudshopservice.shop;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class RpcShopServe {
// 线程池中的线程最终完成方法的调用
private final ExecutorService executorService = Executors.newFixedThreadPool(10);
public void publishService(Object service,int port){
ServerSocket socket = null;
try{
// 服务端监听8080 端口
socket = new ServerSocket(port);
while (true){
// 当有客户端连接进入后发起线程进行数据的处理
Socket socket1 =socket.accept();
executorService.execute(new ProcessHandler(socket1,service));
}
}catch (Exception e){
}finally {
// 最终关闭连接
if (null != socket){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
1.6 具体业务处理:
package com.example.springcloudshopservice.shop;
import org.example.service.RpcRequest;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.Socket;
public class ProcessHandler implements Runnable {
// 定义通信的socket
private Socket socket;
// 定义具体服务方法的实现类型
private Object service;
public ProcessHandler(Socket socket, Object service) {
this.socket = socket;
this.service = service;
}
@Override
public void run() {
ObjectInputStream inputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
// 通过socket 获取客户端的请求数据
inputStream = new ObjectInputStream(socket.getInputStream());
// 获取请求的参数
RpcRequest request = (RpcRequest) inputStream.readObject();
// 反射调用方法,获取对应方法的数据
Object res = invokeMenthod(request);
System.out.println("res = " + res);
// 将方法的结果通过socket 写回到客户端
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(res);
objectOutputStream.flush();
} catch (Exception e) {
// 关闭流
if (null != inputStream) {
try {
inputStream.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
if (null != objectOutputStream) {
try {
objectOutputStream.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
private Object invokeMenthod(RpcRequest request) throws Exception {
// 找到请求方法
Class classz = Class.forName(request.getClassName());
Method method = classz.getMethod(request.getMethodName(), request.getTypes());
// 反射调用方法
return method.invoke(service, request.getArgs());
}
}
1.7 测试类:
package com.example.springcloudshopservice.shop;
import org.example.service.ShopService;
public class ShopTest {
public static void main(String[] args) {
ShopService shopService = new ShopServiceImpl();
RpcShopServe rpcShopServe = new RpcShopServe();
rpcShopServe.publishService(shopService,8080);
}
}
2 订单服务方法调用:
2.1 订单服务模块maven pom 增加api 模块的依赖项;
2.2 构建动态代理,使得订单服务在调用api 中的方法时,通过代理的方式实现:
import java.lang.reflect.Proxy;
public class RpcProxyClient {
// 构建代理,interfaceCls 调用类,host,port 要调用服务的ip 和端口
public <T> T clientProxy(final Class<T> interfaceCls,final String host,final int port){
return (T) Proxy.newProxyInstance(interfaceCls.getClassLoader(),
new Class<?>[]{interfaceCls}, new RemoteInvocationHandler(host, port));
}
}
远程通信建立:
import org.example.service.RpcRequest;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class RemoteInvocationHandler implements InvocationHandler {
private String host;
private int port;
public RemoteInvocationHandler(String host, int port) {
this.host = host;
this.port = port;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 建立远程通信连接
RpcNetTransport rpcNetTransport = new RpcNetTransport(host,port);
RpcRequest request = new RpcRequest();
request.setClassName(method.getDeclaringClass().getName());
request.setMethodName(method.getName());
request.setTypes(method.getParameterTypes());
request.setArgs(args);
// 发送对应服务信息
return rpcNetTransport.send(request);
}
}
建立socket 完成通信:
import org.example.service.RpcRequest;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
public class RpcNetTransport {
private String host;
private int port;
public RpcNetTransport(String host, int port) {
this.host = host;
this.port = port;
}
public Socket getSocket() throws IOException {
// 同服务端建立连接
return new Socket(host, port);
}
// 发送数据到服务端
public Object send(RpcRequest request){
Socket socket = null;
ObjectInputStream inputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
socket = getSocket();
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(request);
objectOutputStream.flush();
// 获取服务端发送的数据并返回
inputStream = new ObjectInputStream(socket.getInputStream());
return inputStream.readObject();
}catch (Exception ex){
ex.printStackTrace();
}finally {
try {
if (null != socket){
socket.close();
}
}catch (Exception e){
}
}
return null;
}
}
测试类:
import org.example.service.ShopService;
public class OrderTest {
public static void main(String[] args) {
RpcProxyClient rpcProxyClient = new RpcProxyClient();
ShopService shopService = rpcProxyClient.clientProxy(ShopService.class,"localhost",8080);
System.out.println("shopService.getOneShop(\"123\") = " + shopService.getOneShop("123"));
}
}
结果:
3 总结:
1) 客户端在调用远程服务方法时,使用动态代理,通过建立socket 连接,发送请求;
2)服务端通过监听对应的端口,获取到客户端的数据,然后通过反射完成方法的调用,并将结果写会到socket中;
3)客户端从sokcet 获取到结果并返回;