Dubbo学习二:手写RPC框架

基本实现思路

必须的角色

  • provider服务提供
  • consumer服务消费
  • registry注册
  • protocol协议

服务提供方

1、定义服务接口和实现类(接口 HelloService)
2、实现类 HelloServiceImpl

public interface HelloServer {
    public String sayHello(String msg);
}

-------------------------------------------------

public class HelloServerImpl implements HelloServer {
    @Override
    public String sayHello(String msg) {
        return msg+"调用了My_rpc的提供方服务";
    }
}

3、服务注册:注册中心

此处注册中心我们将服务注册在 map集合中,结构:Map<String,Map<URL,Class>>
外边 map key存储服务接口的全类名 ,URL 封装了调用服务的 ip port, 里边 value 指定指定具体实现类的全类名
4、启动服务:暴漏服务
------------------------------------注册中心----------------------------------
import java.util.HashMap;
import java.util.Map;
import com.lf.pojo.URL;

public class NativeRegistry {
    /**
     * 注册中心
     */
    public static Map<String, Map<URL,Class>> registCenter=new HashMap<String, Map<URL,Class>>();

    /**
     * 注册服务
     */

        public static <url> void regist(String name,URL url, Class implClass){
        Map<URL,Class> map=new HashMap<URL,Class>();
        map.put(url,implClass);
        registCenter.put(name,map);
    }


    /**
     * 获取服务
     */
    public static Class get(String name, URL url){
        Map<URL,Class> map=registCenter.get(name);
        return map.get(url);
    }

}

---------------------------URL类定义---------------------------------------

import java.util.Objects;

public class URL {
    private String hostName;
    private String port;

    public String getHostName() {
        return hostName;
    }

    public void setHostName(String hostName) {
        this.hostName = hostName;
    }

    public String getPort() {
        return port;
    }

    public void setPort(String port) {
        this.port = port;
    }

    public URL(String hostName, String port) {
        this.hostName = hostName;
        this.port = port;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        URL url = (URL) o;
        return hostName.equals(url.hostName) &&
                port.equals(url.port);
    }

    @Override
    public int hashCode() {
        return Objects.hash(hostName, port);
    }
}


------------------------------启动服务提供类注册服务并暴露服务-----------------

import com.lf.HttpServer;
import com.lf.pojo.URL;
import com.lf.reistry.NativeRegistry;
import com.lf.server.HelloServer;
import com.lf.server.Impl.HelloServerImpl;

public class ServerProvider {

    public static void main(String[] args) {
        //注册服务
        URL url=new URL("localhost","8080");
        NativeRegistry.regist(HelloServer.class.getName(),url, HelloServerImpl.class);

        //暴漏服务
        HttpServer httpServer=new HttpServer();
        httpServer.start(url.getHostName(),Integer.valueOf(url.getPort()));

    }
}

-------------------、
protocol协议
服务之间调用的通信协议采用http协议,所以在服务provider中启动tomcat暴露服务
添加内嵌tomcat的依赖
--------------------

    <dependencies>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>9.0.12</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
    </dependencies>




----------------------------------创建HttpServer-----------------------------------


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;

public class HttpServer {

    /*** tomcat服务启动 * 参考tomcat配置 * <Server port="8005" shutdown="SHUTDOWN"> * <Service name="Catalina"> * <Connector port="8080" protocol="HTTP/1.1" * connectionTimeout="20000" * redirectPort="8443" * URIEncoding="UTF-8"/> * <Engine name="Catalina" defaultHost="localhost"> * <Host name="localhost" appBase="webapps"*/

    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); context.addLifecycleListener(new Tomcat.FixContextListener());
        // 生命周期 监听器 然后按照server.xml,一层层把子节点添加到父节点
        host.addChild(context);
        engine.addChild(host);
        service.setContainer(engine); service.addConnector(connector);
        // service在getServer时就被添加到server节点了

        // tomcat是一个servlet,设置路径与映射
        tomcat.addServlet(contextPath,"dispatcher",new DispatcherServlet()); context.addServletMappingDecoded("/*","dispatcher");
        try {
            tomcat.start();
            // 启动tomcat
            tomcat.getServer().await();
            // 接受请求
        }catch (LifecycleException e){
            e.printStackTrace();
        }
    }
}

---------------------------------------HttpServerHandler处理远程调用请求------------------
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class DispatcherServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        new HttpServerHander().handler(req,resp);

    }
}


import com.lf.pojo.Invocation;
import com.lf.pojo.URL;
import com.lf.reistry.NativeRegistry;
import org.apache.commons.io.IOUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.lang.reflect.Method;

public class HttpServerHander {
    public void handler(HttpServletRequest req, HttpServletResponse resp){
        try{
            // Http请求流转为对象
            InputStream is = req.getInputStream();
            ObjectInputStream ois = new ObjectInputStream(is);
            Invocation invocation = (Invocation)ois.readObject();
            // 寻找注册中心的实现类,通过反射执行方法
            Class implClass = NativeRegistry.get(invocation.getInterfaceName(),new URL("localhost","8080"));
            Method method = implClass.getMethod(invocation.getMethodName(),invocation.getParamTypes());
            String result = (String) method.invoke(implClass.newInstance(),invocation.getParams());
            // 将结果返回
            IOUtils.write(result,resp.getOutputStream());
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}


-----------------------封装调用参数Invocation--------------

import java.io.Serializable;
public class Invocation implements Serializable {
    private String interfaceName;
    private String methodName;
    private Object[] params;
    private Class[] paramTypes;

    public String getInterfaceName() {
        return interfaceName;
    }

    public void setInterfaceName(String interfaceName) {
        this.interfaceName = interfaceName;
    }

    public String getMethodName() {
        return methodName;
    }

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

    public Object[] getParams() {
        return params;
    }

    public void setParams(Object[] params) {
        this.params = params;
    }

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

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





5、服务消费端

封装httpclent对象,发起远端调用

import com.lf.pojo.Invocation;
import com.lf.server.HelloServer;

public class ConsumerMain {

    public static void main(String[] args) {
        Invocation invocation=new Invocation(HelloServer.class.getName(),"sayHello",new Object[]{"myRPC客户端"},new Class[]{String.class});
        Httpclient httpclient=new Httpclient();
        String result =httpclient.post("localhost",8080,invocation);
        System.out.println(result);
    }
}





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;

public class Httpclient {
    public String post(String hostname, Integer port, Invocation invocation) {
        try {
            // 进行http连接
            URL url = new URL("http",hostname,port,"/client/");
            HttpURLConnection connection = (HttpURLConnection)url.openConnection();
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            // 必填项 // 将对象写入输出流
            OutputStream os = connection.getOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(os);
            oos.writeObject(invocation);
            oos.flush();
            oos.close();
            // 将输入流转为字符串(此处可是java对象)
            InputStream is = connection.getInputStream();
            return IOUtils.toString(is);
        }catch (MalformedURLException e){
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }
        return null;
    }

}



public interface HelloServer {
    public String sayHello(String msg);
}






import java.io.Serializable;

public class Invocation implements Serializable {
    private String interfaceName;
    private String methodName;
    private Object[] params;
    private Class[] paramTypes;

    public String getInterfaceName() {
        return interfaceName;
    }

    public void setInterfaceName(String interfaceName) {
        this.interfaceName = interfaceName;
    }

    public String getMethodName() {
        return methodName;
    }

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

    public Object[] getParams() {
        return params;
    }

    public void setParams(Object[] params) {
        this.params = params;
    }

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

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

    public Invocation(String interfaceName, String methodName, Object[] params, Class[] paramTypes) {
        this.interfaceName = interfaceName;
        this.methodName = methodName;
        this.params = params;
        this.paramTypes = paramTypes;
    }
}

执行结果

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值