2020-08-29_基于 web请求的远程调用学习

2021-03-14  本文已影响0人  kikop

基于 web请求的远程调用学习

1概述

本文模拟远程过程调用进行实战总结,总的内容如下;

  1. 抽查接口公共部分
  2. 服务端,提供指定的服务列表(基于服务端提供的服务包路径并进行包扫描,根据服务实现类的注解类及注解方法进行过滤)
  3. 客户端封装请求参数为序列化对象,基于原生Socket进行发送请求
  4. 服务端对请求进行发序列化,并进行解析处理及结果返回

我的另外一篇文章是基于netty通讯框架,并结合zookeeper进行服务的负载均衡进行改写的,感兴趣的朋友可以借鉴,地址: https://www.jianshu.com/p/78b5f3b2a823
,里面也是完整的源码,直接放入工程即可运行,调试。

2公共部分

2.1注解定义

2.1.1RpcClazzAnno

package com.kikop.common.rpc.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author kikop
 * @version 1.0
 * @project Name: MySimpledRpcBasedTomcat
 * @file Name: RpcClazzAnno
 * @desc 功能描述 服务类注解
 * @date 2020/8/23
 * @time 17:21
 * @by IDE: IntelliJ IDEA
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface RpcClazzAnno {
}

2.1.2RpcMethodAnno

package com.kikop.common.rpc.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author kikop
 * @version 1.0
 * @project Name: MySimpledRpcBasedTomcat
 * @file Name: RpcMethodAnno
 * @desc 功能描述 服务类中方法注解
 * @date 2020/8/23
 * @time 17:21
 * @by IDE: IntelliJ IDEA
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RpcMethodAnno {
}

2.2通讯结构体

2.2.1请求

package com.kikop.common.rpc.model;

import java.io.Serializable;

/**
 * @author kikop
 * @version 1.0
 * @project Name: MySimpledRpcBasedTomcat
 * @file Name: MyRpcReqInfo
 * @desc 功能描述 RPC通信请求数据结构
 * @date 2020/8/23
 * @time 16:52
 * @by IDE: IntelliJ IDEA
 */
public class MyRpcReqInfo implements Serializable {

    private static final long serialVersionUID = 5774354750836094390L;

    /**
     * 包名:com.kikop.myrpcdiy.advancedBasedNetty.server.provider
     *
     */
    private String packetName;

    /**
     * 仅仅类名
     * simpled:OrderImpl、IOrder and so on
     * advanced:com.kikop.myrpcdiy.advancedBasedNetty.server.provider.IOrder
     */
    private String clazzName;

    /**
     * 方法名
     */
    private String methodName;

    /**
     * 方法参数值列表
     */
    private Object[] args;

    /**
     * 方法参数类型集合
     */
    private Class<?>[] paramTypes;


    public Class<?>[] getParamTypes() {
        return paramTypes;
    }

    public void setParamTypes(Class<?>[] paramTypes) {
        this.paramTypes = paramTypes;
    }

    private String additionInfo;

    public String getAdditionInfo() {
        return additionInfo;
    }

    public void setAdditionInfo(String additionInfo) {
        this.additionInfo = additionInfo;
    }

    public Object[] getArgs() {
        return args;
    }

    public void setArgs(Object[] args) {
        this.args = args;
    }

    public String getPacketName() {
        return packetName;
    }

    public void setPacketName(String packetName) {
        this.packetName = packetName;
    }

    public String getClazzName() {
        return clazzName;
    }

    public void setClazzName(String clazzName) {
        this.clazzName = clazzName;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

}

2.2.2响应

package com.kikop.common.rpc.model;

import java.io.Serializable;

/**
 * @author kikop
 * @version 1.0
 * @project Name: MySimpledRpcBasedTomcat
 * @file Name: MyRpcReqInfo
 * @desc 功能描述 RPC通信响应结构
 * @date 2020/8/23
 * @time 16:52
 * @by IDE: IntelliJ IDEA
 */
public class MyRpcRespInfo implements Serializable {


    private static final long serialVersionUID = 6027658366486943598L;


    /**
     * 请求方法名
     */
    private String methodName;

    /**
     * 请求结果
     */
    private Object result;

    private String additionInfo;

    public String getAdditionInfo() {
        return additionInfo;
    }

    public void setAdditionInfo(String additionInfo) {
        this.additionInfo = additionInfo;
    }


    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public Object getResult() {
        return result;
    }

    public void setResult(Object result) {
        this.result = result;
    }
}

2.3注解工具类

package com.kikop.common.rpc;


import com.alibaba.fastjson.JSONObject;
import com.kikop.common.rpc.annotations.RpcClazzAnno;
import com.kikop.common.rpc.annotations.RpcMethodAnno;

import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author kikop
 * @version 1.0
 * @project Name: MySimpledRpcBasedTomcat
 * @file Name: MyAnnotationUtil
 * @desc 功能描述 注解读取工具类
 * @date 2020/8/23
 * @time 17:24
 * @by IDE: IntelliJ IDEA
 */
public class MyAnnotationUtil {


    /**
     * 获取包中指定类注解的指定方法
     *
     * @param basePackage 包名 com.kikop.simpledBasedTomcat.service
     * @return {"com.kikop.simpledBasedTomcat.service.OrderImpl":
     * [{"getName":[]},
     * {"setName":["String"]},
     * {"getOrderCount":["String","Integer"]}
     * ]
     * }
     * @throws ClassNotFoundException
     */
    public static Map<String, List<Map<String, List<String>>>> parse(String basePackage) throws ClassNotFoundException {

        Map<String, List<Map<String, List<String>>>> resultClazzMap = new HashMap<>();

        // 1.获取当前注解所在的资源classPath类路径:
        // /E:/workdirectory/Dev/study/MySimpledRpcBasedTomcat/target/classes/
        String rootPath = MyAnnotationUtil.class.getResource("/").getPath();

        // 1.1.转换包路径到文件结构:
        // :com/kikop/simpledBasedTomcat/service
        String basePacketPath = basePackage.replace(".", "/");

        // 1.2.构造File对象
        // /E:/workdirectory/Dev/study/MySimpledRpcBasedTomcat/target/classes/com/kikop/simpledBasedTomcat/service
        String packagePathName = rootPath + basePacketPath;
        File file = new File(packagePathName);

        // 2.遍历包下的所有文件
        // 2.1.遍历得到文件名列表
        // [0]:OrderImpl.class
        String[] names = file.list();
        for (String fileName : names) {

            // OrderImpl.class--> OrderImpl
            String className = fileName.replaceAll(".class", "");

            // com.kikop.simpledBasedTomcat.service.OrderImpl
            String fullClazzName = basePackage + "." + className;
            Class<?> aClass = Class.forName(fullClazzName);

            if (aClass.isAnnotationPresent(RpcClazzAnno.class)) { // 指定类上的注解
                Method[] declaredMethods = aClass.getDeclaredMethods();

                List<Map<String, List<String>>> resulMethodsWithinClazzMap = new ArrayList<>();

                // 2.1.遍历类上定义的需要对外提供服务的方法,并缓存到MethodMap中
                for (Method declaredMethod : declaredMethods) {

                    if (declaredMethod.isAnnotationPresent(RpcMethodAnno.class)) { // 指定方法上的注解

                        //1.1.Map:key 包名+类名,v:方法列表
                        // key:方法名
                        // value:方法参数类型
                        Map<String, List<String>> methodMap = new HashMap<>();

                        List<String> params = new ArrayList<>(); // 方法的参数列表
                        Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
                        for (Class<?> parameterType : parameterTypes) {
                            String simpleName = parameterType.getSimpleName();
                            params.add(simpleName);
                        }
                        methodMap.put(declaredMethod.getName(), params);
                        resulMethodsWithinClazzMap.add(methodMap);
                    }
                }
                // key:com.kikop.simpledBasedTomcat.service.OrderImpl
                // value:resulMethodsWithinClazzMap
                resultClazzMap.put(fullClazzName, resulMethodsWithinClazzMap);
            }
        }
//        System.out.println(JSONObject.toJSON(resultClazzMap));
        return resultClazzMap;
    }

    public static void main(String[] args) throws ClassNotFoundException {

        MyAnnotationUtil.parse(ServerConfig.BASEPACKAGE);
    }
}

2.3.1打印服务端服务列表

[图片上传失败...(image-ce4126-1615726129915)] image-20210314190740255.png

2.4原生socket接口封装

package com.kikop.common.rpc;

import com.kikop.common.rpc.model.MyRpcReqInfo;
import com.kikop.common.rpc.model.MyRpcRespInfo;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Arrays;

/**
 * @author kikop
 * @version 1.0
 * @project Name: MySimpledRpcBasedTomcat
 * @file Name: MySocketUtils
 * @desc 功能描述 socket数据序列化发送
 * @date 2021/3/13
 * @time 17:24
 * @by IDE: IntelliJ IDEA
 */
public class MySocketUtils {

    /**
     * 获取请求元数据
     *
     * @param currentSocket
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static MyRpcReqInfo getReqMetaData(Socket currentSocket) throws IOException, ClassNotFoundException {

        // 1.获取远程请求参数并反序列化
        ObjectInputStream objectInputStream = new ObjectInputStream(currentSocket.getInputStream());
        MyRpcReqInfo myRpcReqInfo = (MyRpcReqInfo) objectInputStream.readObject();
        return myRpcReqInfo;
    }

    /**
     * 发送请求元数据
     *
     * @param currentSocket
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static void sendReqMetaData(Socket currentSocket, MyRpcReqInfo myRpcReqInfo) throws IOException, ClassNotFoundException {

        // 1.获取通道写入流
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(currentSocket.getOutputStream());
        // 2.发起请求
        objectOutputStream.writeObject(myRpcReqInfo);
        // 提交
        objectOutputStream.flush();
        // 关闭输出流
        currentSocket.shutdownOutput();

        // 3.获取输入流,并读取服务器端的响应信息
        ObjectInputStream objectInputStream = new ObjectInputStream(currentSocket.getInputStream());
        Object respResult = objectInputStream.readObject();
        if (respResult instanceof MyRpcRespInfo) {
            MyRpcRespInfo myRpcRespInfo = (MyRpcRespInfo) respResult;

            System.out.println(String.format("taskInfo:[%s],reqClazzInfo:[%s.%s:%s]-->reqResult:%s",
                    myRpcReqInfo.getAdditionInfo(),
                    myRpcReqInfo.getClazzName(), myRpcReqInfo.getMethodName(), Arrays.toString(myRpcReqInfo.getArgs()),
                    String.valueOf(myRpcRespInfo.getResult())));
        }
        //4.关闭资源
        objectOutputStream.close();
        objectInputStream.close();
        currentSocket.close();
    }

    /**
     * 发送请求结果
     *
     * @param currentSocket
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static void sendRespResult(Socket currentSocket, MyRpcRespInfo myRpcRespInfo) throws IOException, ClassNotFoundException {

        // 1.获取输出流,向服务器端发送信息
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(currentSocket.getOutputStream());

        // 2.发起请求
        objectOutputStream.writeObject(myRpcRespInfo);

        // 3.提交并关闭流
        objectOutputStream.flush();
        objectOutputStream.close();
    }


}

2.5服务参数配置

package com.kikop.common.rpc;

/**
 * @author kikop
 * @version 1.0
 * @project Name: MySimpledRpcBasedTomcat
 * @file Name: ServerConfig
 * @desc 功能描述 服务配置类,定义对外抛出的服务
 * @date 2020/8/23
 * @time 17:21
 * @by IDE: IntelliJ IDEA
 */
public class ServerConfig {

    public final static String HOST = "127.0.0.1";
    public final static int PORT = 6666;

    public static final String BASEPACKAGE = "com.kikop.simpledBasedTomcat.service";



}

3服务端

3.1maven依赖

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.kikop</groupId>
    <artifactId>MySimpledRpcBasedTomcat</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>MySimpledRpcBasedTomcat Webapp</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>

        <fastjson.version>1.2.29</fastjson.version>

        <!-- slf4j日志文件管理包版本 -->
        <slf4j.version>1.7.12</slf4j.version>

        <!--jstl -->
        <jstl.version>1.2</jstl.version>

    </properties>

    <dependencies>

        <!--1.单元测试类-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>

        <!--2.servlet-api-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>


        <!--3.fastjson-->
        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>


        <!--4.JSTL标签类-->
        <!--<dependency>-->
        <!--<groupId>jstl</groupId>-->
        <!--<artifactId>jstl</artifactId>-->
        <!--<version>${jstl.version}</version>-->
        <!--</dependency>-->

        <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/jsp-api -->
        <!--<dependency>-->
        <!--<groupId>javax.servlet.jsp</groupId>-->
        <!--<artifactId>jsp-api</artifactId>-->
        <!--<version>2.2</version>-->
        <!--<scope>provided</scope>-->
        <!--</dependency>-->

        <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
        <!--<dependency>-->
        <!--<groupId>javax.servlet.jsp</groupId>-->
        <!--<artifactId>javax.servlet.jsp-api</artifactId>-->
        <!--<version>2.3.0</version>-->
        <!--<scope>provided</scope>-->
        <!--</dependency>-->


        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <!--<dependency>-->
        <!--<groupId>javax.servlet</groupId>-->
        <!--<artifactId>javax.servlet-api</artifactId>-->
        <!--<version>3.1.0</version>-->
        <!--<scope>provided</scope>-->
        <!--</dependency>-->


    </dependencies>

    <build>
        <finalName>MySimpledRpcBasedTomcat</finalName>

        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->

            <plugins>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>3.2.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

</project>

3.2对外接口服务

注意,对外接口服务统一放在:com.kikop.simpledBasedTomcat.service这个包路径下。

package com.kikop.simpledBasedTomcat.service;

import com.kikop.common.rpc.annotations.RpcClazzAnno;
import com.kikop.common.rpc.annotations.RpcMethodAnno;


/**
 * @author kikop
 * @version 1.0
 * @project Name: MySimpledRpcBasedTomcat
 * @file Name: OrderImpl
 * @desc 功能描述 模拟对外提供的订单服务
 * @date 2020/8/23
 * @time 17:21
 * @by IDE: IntelliJ IDEA
 */
@RpcClazzAnno
public class OrderImpl {

    private String orderName;

    @RpcMethodAnno
    public String getOrderName() {
        return orderName;
    }

    @RpcMethodAnno
    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }

    @RpcMethodAnno
    public Integer getOrderCount(String orderName) {

        if (orderName.equalsIgnoreCase("apple")) {
            return 100;
        }
        return 10;
    }
}

3.3调度层

3.3.1服务端业业务处理

package com.kikop.simpledBasedTomcat.dispatcher;


import com.kikop.common.rpc.MySocketUtils;
import com.kikop.common.rpc.model.MyRpcReqInfo;
import com.kikop.common.rpc.model.MyRpcRespInfo;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.Arrays;

/**
 * @author kikop
 * @version 1.0
 * @project Name: MySimpledRpcBasedTomcat
 * @file Name: ServerThread
 * @desc 功能描述
 * @date 2020/8/23
 * @time 17:02
 * @by IDE: IntelliJ IDEA
 */
public class ServerTaskHandler implements Runnable {

    private Socket currentSocket;

    public ServerTaskHandler(Socket currentSocket) {
        this.currentSocket = currentSocket;
    }

    @Override
    public void run() {

        try {

            // 1.获取远程请求参数并反序列化
            MyRpcReqInfo myRpcReqInfo = MySocketUtils.getReqMetaData(currentSocket);

            // 2.反射得到类信息
            Class<?> aClass = Class.forName(myRpcReqInfo.getPacketName() + "." + myRpcReqInfo.getClazzName());
            Class[] params = new Class[myRpcReqInfo.getArgs().length];
            for (int i = 0; i < params.length; i++) {
                params[i] = myRpcReqInfo.getArgs()[i].getClass();
            }
            Method method = aClass.getMethod(myRpcReqInfo.getMethodName(), params);
            Object result = method.invoke(aClass.newInstance(), myRpcReqInfo.getArgs());
            System.out.println(String.format("taskInfo:[%s],reqClazzInfo:[%s.%s:%s]-->reqResult:%s",
                    myRpcReqInfo.getAdditionInfo(),
                    method.getDeclaringClass().getName(), method.getName(), Arrays.toString(myRpcReqInfo.getArgs()),
                    result)
            );

            //3.返回结果
            MyRpcRespInfo myRpcRespInfo = new MyRpcRespInfo();
            myRpcRespInfo.setMethodName(method.getName());
            myRpcRespInfo.setResult(result);
            myRpcRespInfo.setAdditionInfo(myRpcReqInfo.getAdditionInfo());
            MySocketUtils.sendRespResult(currentSocket, myRpcRespInfo);

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }
}

3.3.2服务管理类

package com.kikop.simpledBasedTomcat.dispatcher;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author kikop
 * @version 1.0
 * @project Name: MySimpledRpcBasedTomcat
 * @file Name: ServerManager
 * @desc 功能描述
 * @date 2020/8/23
 * @time 16:33
 * @by IDE: IntelliJ IDEA
 */
public class ServerManager {

    private int totalClientCount = 0;

    /**
     * 启动服务
     *
     * @param port
     * @throws IOException
     */
    public void startSvr(int port) throws IOException {

        totalClientCount = 0;
        ServerSocket serverSocket = new ServerSocket(port);

        // 创建5个固定的线程
        // 使用 LinkedBlockingQueue队列管理等待数据
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        System.out.println("服务器即将启动,等待客户端的连接 ...");

        while (true) {
            Socket clientSocket = serverSocket.accept();
            executorService.execute(new ServerTaskHandler(clientSocket));

//            System.out.println(String.format("a client connect success,getRemoteSocketAddress%s-->getLocalSocketAddress:%s!"
//                    , clientSocket.getRemoteSocketAddress().toString(), clientSocket.getLocalSocketAddress().toString())
//            );

            totalClientCount++;//统计客户端的数量
            InetAddress clientSocketInetAddress = clientSocket.getInetAddress(); // clientSocketInetAddress.getHostAddress()
            System.out.println(String.format("客户端的数量:%d,当前客户端的信息%s", totalClientCount,
                    clientSocket.getRemoteSocketAddress().toString()));
        }
    }
}

3.4控制层

控制层接收客户端web请求,客户端通过浏览器登录,输入服务接口访问即可,控制层主要是向客户端展示当前可用的服务列表。

package com.kikop.simpledBasedTomcat.Controller;

import com.alibaba.fastjson.JSON;
import com.kikop.common.rpc.MyAnnotationUtil;
import com.kikop.common.rpc.ServerConfig;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;

/**
 * @author kikop
 * @version 1.0
 * @project Name: MySimpledRpcBasedTomcat
 * @file Name: SimpledRpcServlet
 * @desc 功能描述 基于tomcat的 htttp协议
 * WebServlet代替 web.xml
 * http://localhost:8080/simpledRpc/simpledRpcServlet
 * @date 2020/8/23
 * @time 18:20
 * @by IDE: IntelliJ IDEA
 */
//@WebServlet(name = "simpledRpcServlet", urlPatterns = "/demo/simpledRpcServlet")
@WebServlet("/simpledRpcServlet")
public class SimpledRpcServlet extends HttpServlet {

    private Map<String, List<Map<String, List<String>>>> resultClazzMap;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //super.service(req, resp);

        // :/simpledRpc/simpledRpcServlet
        System.out.println(req.getRequestURI());

        // :http://localhost:8080/simpledRpc/simpledRpcServlet
        System.out.println(req.getRequestURL());

        String reqServerName = req.getParameter("reqServerName");
        try {
            if (resultClazzMap != null) {
                if (reqServerName == null) {
                    responseData(resp, resultClazzMap);
                } else {
                    List<Map<String, List<String>>> maps = resultClazzMap.get(reqServerName);
                    responseData(resp, maps);
                }
            } else {
                resultClazzMap = MyAnnotationUtil.parse(ServerConfig.BASEPACKAGE);
                if (reqServerName == null) {
                    responseData(resp, resultClazzMap);
                } else {
                    List<Map<String, List<String>>> maps = resultClazzMap.get(reqServerName);
                    responseData(resp, (maps == null) ? new Object() : maps);

                }
            }

        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }

    }

    /**
     * 发送请求结果
     *
     * @param resp
     * @param javaObject
     * @throws IOException
     */
    private void responseData(HttpServletResponse resp, Object javaObject) throws IOException {
        PrintWriter pw = resp.getWriter();
        pw.println(JSON.toJSON(javaObject));
        pw.flush();
        pw.close();
    }


}

4客户端

由于客户端只需要登录浏览器即可,没用额外接口开发,只需建立正常的socket连接,发送标准的序列化请求结构即可。

4测试

4.1启动服务端

package com.kikop.simpledBasedTomcat.SimpledRpcTest;


import com.kikop.common.rpc.ServerConfig;
import com.kikop.simpledBasedTomcat.dispatcher.ServerManager;

import java.io.IOException;

/**
 * @author kikop
 * @version 1.0
 * @project Name: MySimpledRpcBasedTomcat
 * @file Name: producerTest
 * @desc 功能描述
 * @date 2020/8/23
 * @time 16:36
 * @by IDE: IntelliJ IDEA
 */
public class producerTest {


    public static void main(String[] args) throws IOException {
        publisherSvrTest();
    }

    private static void publisherSvrTest() throws IOException {

        ServerManager serverManager = new ServerManager();
        serverManager.startSvr(ServerConfig.PORT);
    }
}

4.2模拟客户端发送请求

package com.kikop.simpledBasedTomcat.SimpledRpcTest;


import com.kikop.common.rpc.MySocketUtils;
import com.kikop.common.rpc.ServerConfig;
import com.kikop.common.rpc.model.MyRpcReqInfo;

import java.io.IOException;
import java.net.Socket;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 * @author kikop
 * @version 1.0
 * @project Name: MySimpledRpcBasedTomcat
 * @file Name: consumerTest
 * @desc 功能描述
 * @date 2020/8/23
 * @time 16:37
 * @by IDE: IntelliJ IDEA
 */
public class consumerTest {


    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {

        IntStream.range(0, 10).parallel().forEach(value -> {
            try {

                String reqTaskInfo = String.format("%s:%d",
                        Thread.currentThread().getName(), Thread.currentThread().getId());
                sendReqMetaData(value, reqTaskInfo);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        });

    }


    /**
     * 模拟查询用户名为kikop的订单信息
     *
     * @return
     */
    private static void sendReqMetaData(int dataType, String reqTaskInfo) throws IOException, ClassNotFoundException {

        // 1.创建一个客户端socket通道
        Socket socket = new Socket(ServerConfig.HOST, ServerConfig.PORT);

        // 2.封装请求参数
        MyRpcReqInfo myRpcReqInfo = new MyRpcReqInfo();
        myRpcReqInfo.setPacketName("com.kikop.simpledBasedTomcat.service");
        myRpcReqInfo.setClazzName("OrderImpl");
        myRpcReqInfo.setMethodName("getOrderCount");
        Object[] args = new Object[]{(dataType % 2 == 0) ? "banana" : "apple"};
        myRpcReqInfo.setArgs(args);
        myRpcReqInfo.setAdditionInfo(reqTaskInfo);

        // 3.发送请求
        MySocketUtils.sendReqMetaData(socket, myRpcReqInfo);

    }


}

参考

上一篇 下一篇

猜你喜欢

热点阅读