学习dubbo准备----手写一个简单的RPC框架

结构图

在这里插入图片描述

代码

代码结构

在这里插入图片描述

服务提供者provider

结构

在这里插入图片描述

核心代码

注册中心
package com.ql.learn.registry;

import com.ql.learn.pojo.URL;

import java.util.HashMap;
import java.util.Map;

/**
 * @author qinlei
 * @description 本地注册中心
 * @date 2020/9/18 17:12
 */
public class NativeRegistry {
    //注册中心
    private static Map<String, Map<URL,Class>> registryCenter = new HashMap<String, Map<URL,Class>>();

    /**
     * 注册服务
     */
    public static void registry(String interfaceName,URL url,Class implClass){
        Map<URL, Class> hashMap = new HashMap<>();
        hashMap.put(url,implClass);
        registryCenter.put(interfaceName,hashMap);
    }

    /**
     * 从注册中心获取服务
     * @param url   请求的路径(ip port)
     * @param interfaceName 接口名称
     * @return
     */
    public static Class get(URL url,String interfaceName){
        return registryCenter.get(interfaceName).get(url);
    }
}

配置tomcat
package com.ql.learn.tomcat;

import org.apache.catalina.*;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.startup.Tomcat;

/**
 * @author qinlei
 * @description 构建一个tomcat
 * @date 2020/9/18 17:24
 */
public class HttpServer {

    public void start(String hostname,Integer port){
        //实例化tomcat
        Tomcat tomcat = new Tomcat();

        //创建server
        Server server = tomcat.getServer();

        //获取service
        Service service = server.findService("Tomcat");

        //构建connector
        Connector connector = new Connector();
        connector.setPort(port);
        connector.setURIEncoding("UTF-8");

        //构建engine
        Engine engine = new StandardEngine();
        engine.setDefaultHost(hostname);

        //构建host
        Host host = new StandardHost();
        host.setName(hostname);

        //构建context
        String contextPath = "";
        Context context = new StandardContext();
        context.setPath(contextPath);
        //tomcat的生命周期监听器
        context.addLifecycleListener(new Tomcat.FixContextListener());

        //一层一层将子节点添加到父节点
        host.addChild(context);
        engine.addChild(host);
        service.setContainer(engine);
        service.addConnector(connector);//这里的service本来就是从server中拿到的

        //tomcat是一个servlet,设置路径和映射
        tomcat.addServlet(contextPath,"dispatcher",new DispatcherServlet());
        context.addServletMappingDecoded("/*","dispatcher");

        try {
            tomcat.start();//启动tomcat
            tomcat.getServer().await();//接受请求
        } catch (LifecycleException e) {
            e.printStackTrace();
        }
    }
}

package com.ql.learn.tomcat;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author qinlei
 * @description todo
 * @date 2020/9/18 17:38
 */
public class DispatcherServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp){
        //处理远程调用请求
        new HttpServerHandler().handle(req,resp);
    }
}

package com.ql.learn.tomcat;

import com.ql.learn.pojo.Invocation;
import com.ql.learn.pojo.URL;
import com.ql.learn.registry.NativeRegistry;
import org.apache.commons.io.IOUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author qinlei
 * @description 处理远程调用请求
 * @date 2020/9/18 17:41
 */
public class HttpServerHandler {
    public void handle(HttpServletRequest req, HttpServletResponse resp) {
        //服务请求处理逻辑
        try {

            //1.通过请求流获取请求服务调用的参数
            InputStream inputStream = req.getInputStream();
            ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
            Invocation invocation = (Invocation) objectInputStream.readObject();

            //2.从注册中心获取服务的列表
            Class implClass = NativeRegistry.get(new URL("localhost",8899),invocation.getInterfaceName());
            //3.调用服务-映射
            Method method = implClass.getMethod(invocation.getMethodName(),invocation.getParamTypes());
            String result = (String) method.invoke(implClass.newInstance(),invocation.getParams());
            //4.返回结果
            IOUtils.write(result,resp.getOutputStream());
        } 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();
        }
    }
}

服务提供者启动类
package com.ql.learn.provider;

import com.ql.learn.pojo.URL;
import com.ql.learn.registry.NativeRegistry;
import com.ql.learn.service.HelloService;
import com.ql.learn.service.impl.HelloServiceImpl;
import com.ql.learn.tomcat.HttpServer;

/**
 * @author qinlei
 * @description todo
 * @date 2020/9/18 17:19
 */
public class ServiceProvider {
    public static void main(String[] args) {
        //真正的注册服务
        URL url = new URL("localhost",8899);
        NativeRegistry.registry(HelloService.class.getName(),url,HelloServiceImpl.class);

        //启动tomcat,暴露服务
        HttpServer httpServer = new HttpServer();
        httpServer.start(url.getHostname(),url.getPort());
    }
}

服务消费者consumer

代码结构

在这里插入图片描述

核心代码

发起远程调用
package com.ql.learn.consumer;


import com.ql.learn.pojo.Invocation;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * @author qinlei
 * @description 发起远程调用
 * @date 2020/9/19 9:02
 */
public class HttpClient {

    public String post(String hostname, int port , Invocation invocation){
        try {
            //进行连接
            URL url = new URL("http",hostname,port,"/client");
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);

            //发送调用信息
            OutputStream ops = connection.getOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(ops);
            oos.writeObject(invocation);
            oos.flush();
            oos.close();

            //将输入流转为字符串(这里可以是java对象) 获取远程调用的结果
            InputStream ins = connection.getInputStream();
           return IOUtils.toString(ins,"UTF-8");
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

消费者入口
package com.ql.learn.consumer;

import com.ql.learn.pojo.Invocation;
import com.ql.learn.service.HelloService;

/**
 * @author qinlei
 * @description todo
 * @date 2020/9/19 9:32
 */
public class ConsumerMain {
    public static void main(String[] args) {
        Object[] params = new Object[1];
        params[0] = "rpcDemo客户端";
        Invocation invocation = new Invocation(HelloService.class.getName(), "sayHello", params, new Class[]{String.class});
        HttpClient httpClient = new HttpClient();
        String post = httpClient.post("localhost", 8899, invocation);
        System.out.println(post);
    }
}


源码地址:

https://github.com/qlanto224/RpcDemo.git

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qlanto

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值