Spring架构篇--2.6 远程通信基础--Rpc-Socket实战篇

前言:微服务之间怎么通过socket完成通信;本文通过demo 展示微服务如何通过socket 完成服务之间的通信;
Spring架构篇--2.6 远程通信基础--Rpc-Socket实战篇_第1张图片
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"));
    }
}

结果:
Spring架构篇--2.6 远程通信基础--Rpc-Socket实战篇_第2张图片
3 总结:
1) 客户端在调用远程服务方法时,使用动态代理,通过建立socket 连接,发送请求;
2)服务端通过监听对应的端口,获取到客户端的数据,然后通过反射完成方法的调用,并将结果写会到socket中;
3)客户端从sokcet 获取到结果并返回;

你可能感兴趣的:(java基础篇,java工具篇,spring,架构,java)