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

news2025/7/30 22:58:48

前言:微服务之间怎么通过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 获取到结果并返回;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/367820.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1080T、2080T、4070T显卡的深度学习性能测试和结论

先说结论&#xff1a; 4070T显卡FP32的训练和推理速度跟3090应该基本类似。但由于显存12G偏低&#xff0c;4070T不太适合如今的深度学习模型训练&#xff08;新手列外&#xff0c;大部分模型都能训练起来&#xff0c;耗电也相对很低&#xff09;&#xff0c;更适合测试最新的一…

记录一次ubuntu下配置ssh登录出现的问题

现象描述: 1. 配置完服务器端公钥和本地的私钥之后&#xff0c;ssh登录始终会让输入密码&#xff0c;用ssh -vvv rootip 查看发现发送密钥之后就没反应了。 本机debug info: debug1: Trying private key: C:\Users\wangc/.ssh/id_xxxx &#xff08;私钥文件&#xff09; debug3…

每日站会如何进行优化流程,更高效?

1、每日站会时间要求 每日站会是开发团队一个以15分钟为限的活动。每日站会每一天的上午9点准时在会议室举行。开会时间需要把握精准&#xff0c;并需要每天坚持进行站会讨论活动。 每日站会如何进行优化流程&#xff0c;更高效&#xff1f;​ 2、团队中站会的角色和职责…

Unity(三)--导入3d模型并实现UGUI界面上嵌入3d模型

Unity支持的常用模型格式及建模软件: 格式建模软件网格动画材质骨骼FBX3DMax,C4D,Blender,Maya等√√√√OBJ3DMax,C4D,Blender,Maya等√目录 导入模型并调整好位置创建2D场景(UGUI)使3d模型显示在图片前面方法一:使用Render Texture注意点导入模型并调整好位置 以FBX为例,…

SAP MM 物料管理模块入门学习笔记 2023.2.24

https://zhuanlan.zhihu.com/p/555022893 SAP 企业组织结构 SAP 物料管理模块企业组织结构从上到下分为 集团——》公司——》工厂——》库存地点 集团&#xff1a;SAP 系统组织结构最高级别&#xff1a;内部包括一个完整的SAP系统全部数据 公司代码&#xff1a; 标识集团内一…

【Kubernetes 企业项目实战】09、Rancher 2.6 管理 k8s-v1.23 及以上版本高可用集群

目录 一、Rancher 介绍 1.1Rancher简介 1.2 Rancher 和 k8s 的区别 1.3 Rancher 企业使用案例 二、安装 Rancher 2.1 初始化环境 2.2 安装 Rancher 2.3 登录 Rancher 平台 三、通过 Rancher 管理已存在的 k8s 集群 3.1 配置 rancher 3.2 导入 k8s ​四、通过 Ranc…

啊哈 算法读书笔记 第 1 章 一大波数正在靠近——排序

目录 排序算法&#xff1a; 时间复杂度&#xff1a; 排序算法和冒泡排序之间的过渡&#xff1a; 冒泡排序 冒泡排序和快速排序之间的过渡&#xff1a; 快速排序 排序算法&#xff1a; 首先出场的是我们的主人公小哼&#xff0c;上面这个可爱的娃就是啦。期末考试完了老…

安装Ffmpeg音视频编解码工具和搭建EasyDarwin开源流媒体服务器

目录 一&#xff0c;安装Ffmpeg音视频编解码工具 1&#xff0c;简介 2&#xff0c;开发文档 3&#xff0c;安装部署 二&#xff0c;搭建EasyDarwin开源流媒体服务器 1&#xff0c;简介 2&#xff0c;主要功能特点 3&#xff0c;安装部署 4&#xff0c;效果图 三&…

「mysql是怎样运行的」第17章 调节磁盘和CPU的矛盾---InnoDB的BufferPool

「mysql是怎样运行的」第17章 调节磁盘和CPU的矛盾—InnoDB的Buffer Pool 文章目录「mysql是怎样运行的」第17章 调节磁盘和CPU的矛盾---InnoDB的Buffer Pool[toc]一、缓存的重要性二、InnoDB的Buffer Pool2.1 啥是Buffer Pool2.2 Buffer Pool内部组成2.3 free链表的管理2.4 缓…

Sallen-Key二阶低通滤波器——设计问题浅析

目录前言1 Sallen-Key二阶低通滤波器结构2 截止频率3 结语前言 这两天接了个简单的活&#xff0c;关于设计一个Sallen-Key二阶低通滤波器&#xff0c;有一些体会。 1 Sallen-Key二阶低通滤波器结构 这个结构很简单&#xff0c;优势就是在于简易实现二阶低通。这种类电压跟随器…

第九届蓝桥杯省赛 C++ B组 - 日志统计

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4da;专栏地址&#xff1a;蓝桥杯题解集合 &#x1f4dd;原题地址&#xff1a;日志统计 &#x1f4e3;专栏定位&#xff1a;为想参加蓝桥杯的小伙伴整理常考算法题解&#xff0c;祝大家…

电脑技巧:分享六个非常实用的资源网站

今天小编给大家分享六个非常实用的资源网站&#xff0c;大家一起来看看吧&#xff01; 1、高清壁纸&#xff1a;Wallhaven 一个免费的高清壁纸下载网站&#xff0c;里面的壁纸资源丰富&#xff0c;更新速度也快&#xff0c;各种类型的壁纸都能找到&#xff0c;尤其是动漫壁纸。…

mars3d常用参数备用

1.多个包围盒计算飞行定位 map.camera.flyToBoundingSphere(boundingSphere) 可以一个数组记录下center&#xff0c;再用http://mars3d.cn/api/Map.html#flyToPositions 2.轨迹漫游实现沿着原轨迹倒退 把播放速率改为负数 3.自带的图层管理里面这个noCenter属性跟flyTo属性区…

动态网站开发讲课笔记02:Java Web概述

文章目录零、本讲学习目标一、 XML基础&#xff08;一&#xff09;XML概述1、XML2、XML与HTML的比较&#xff08;二&#xff09;XML语法1、XML文档的声明2、XML元素的定义3、XML属性的定义4、XML注释的定义5、XML文件示例&#xff08;三&#xff09;DTD约束1、什么是XML约束2、…

做出改变:农业科技和区块链在为地球的未来而战中的力量

到2050年&#xff0c;全球有100亿人需要养活&#xff0c;全世界都在关注区块链和农业信息化&#xff0c;以推动发展中国家的技术革新。 自成立以来&#xff0c;区块链技术已经找到了多样化和有价值的应用&#xff0c;以帮助提高效率和激励社区在不同领域和行业的参与。 农业是…

【华为OD机试模拟题】用 C++ 实现 - 去除多余空格(2023.Q1)

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…

《Linux运维实战:Centos7.6基于ansible一键离线部署rabbitmq3.9.16镜像模式集群》

一、部署背景 由于业务系统的特殊性&#xff0c;我们需要针对不同的客户环境部署 rabbitmq镜像模式集群&#xff0c;由于大都数用户都是专网环境&#xff0c;无法使用外网&#xff0c;为了更便捷&#xff0c;高效的部署&#xff0c;针对业务系统的特性&#xff0c;我这边编写了…

git cherry-pick could not apply fb2cde669...问题解决

最近多个分支修复bug&#xff0c;在使用git cherry-pick进行小功能合并时经常会出现类似could not apply fb2cde669...的错误。具体如下图&#xff1a;具体原因是cherry-pick指定的commit内容中和当前分支有冲突导致的。具体解决分以下步骤&#xff1a;1&#xff1a;首先使用gi…

DeepLabV3+:对预测处理的详解

相信大家对于这一部分才是最感兴趣的&#xff0c;能够实实在在的看到效果。这里我们就只需要两个.py文件&#xff08;deeplab.py、predict_img.py&#xff09;。 创建DeeplabV3类 deeplab.py的作用是为了创建一个DeeplabV3类&#xff0c;提供一个检测图片的方法&#xff0c;而…

数据结构与算法入门

目录数据结构概述逻辑结构存储结构算法概述如何理解“大O记法”时间复杂度空间复杂度数据结构概述 数据结构可以简单的理解为数据与数据之间所存在的一些关系&#xff0c;数据的结构分为数据的存储结构和数据的逻辑结构。 逻辑结构 集合结构&#xff1a;数据元素同属于一个集…