');}

自己实现一个Dubbo

Author Avatar
Rico 12月 20, 2018

Dubbo

Dubbo是一款高性能轻量级的开源Java RPC框架

什么是RPC?

远程过程调用。

HTTP也是一种RPC协议 TCP也是

传统的HTTP调用

需要关心地址,地址变了消费端也要跟着变 ,需要字符串转换等缺点

RPC式的调用

consumer配置

provider配置

特别简单,作为消费者不需要关心地址

dubbo可扩展,它支持多种协议

自己实现

本项目就不采用模块的形式了(可以采用模块的形式) ,采用包代替模块的方式

我们注册中心一般用zookeeper或者eureka 或者redis ,注册中心也是可以扩展的

我们自己实现一个注册中心

注册中心要实现的是保存服务配置,需要保存: 服务名, url, 服务的实现类

形如

  1. {
  2. 服务名://因为可能有多个提供者
  3. {URL:服务实现类},
  4. {URL:服务实现类}
  5. }

我们用hashmap来存

一个Java对象要在网络中进行传输,需要序列化

部分源码

注册中心

采用一个hashmap来充当注册中心. 注册中心是独立于服务提供方和服务消费方的,但是这里为了省事,放在同一个工程中了

  1. package org.rico.learnDubbo.register;
  2. import org.rico.learnDubbo.framework.URL;
  3. import java.util.HashMap;
  4. import java.util.Map;
  5. /**
  6. * 自己实现的一个注册中心,采用map
  7. * Created by Rico on 2018/12/20.
  8. */
  9. public class RegisterServer {
  10. private static Map<String,Map<URL,Class>> REGISTER =new HashMap<String,Map<URL,Class>>();
  11. //注册服务
  12. public static void register(URL url,String interfaceName,Class implClass){//需要传入URL,服务名,接口名(interface),实现类
  13. Map<URL,Class> map=new HashMap<URL,Class>();
  14. map.put(url,implClass);
  15. System.out.println("服务注册成功!注册的服务接口名为:"+interfaceName+",所在接口类为:"+implClass.getName());
  16. REGISTER.put(interfaceName,map);
  17. }
  18. public static Class get(URL url,String interfaceName){
  19. return REGISTER.get(interfaceName).get(url);
  20. }
  21. //获取可用服务
  22. public static URL get(String interfaceName){
  23. return null;
  24. }
  25. }

传输协议

http

  1. package org.rico.learnDubbo.protocol.http;
  2. import javax.servlet.ServletException;
  3. import javax.servlet.http.HttpServlet;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.IOException;
  7. /**
  8. * Created by Rico on 2018/12/20.
  9. */
  10. public class DispatcherServlet extends HttpServlet {
  11. @Override
  12. protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  13. //super.service(req, resp);
  14. new HttpServerHandler().handler(req,resp);
  15. }
  16. }
  1. package org.rico.learnDubbo.protocol.http;
  2. import org.apache.commons.io.IOUtils;
  3. import org.rico.learnDubbo.framework.TransferModel;
  4. import org.rico.learnDubbo.framework.URL;
  5. import org.rico.learnDubbo.register.RegisterServer;
  6. import javax.servlet.http.HttpServletRequest;
  7. import javax.servlet.http.HttpServletResponse;
  8. import java.io.IOException;
  9. import java.io.InputStream;
  10. import java.io.ObjectInputStream;
  11. import java.io.OutputStream;
  12. import java.lang.reflect.InvocationTargetException;
  13. import java.lang.reflect.Method;
  14. /**
  15. * Created by Rico on 2018/12/20.
  16. */
  17. public class HttpServerHandler{
  18. //处理请求和响应
  19. public void handler(HttpServletRequest req, HttpServletResponse resp){
  20. //对象通过网络传输
  21. InputStream inputStream= null;
  22. try {
  23. inputStream = req.getInputStream();
  24. ObjectInputStream objectInputStream=new ObjectInputStream(inputStream);
  25. TransferModel transferModel =(TransferModel)objectInputStream.readObject();//二进制数据反序列化成一个对象
  26. //根据transferModel中的信息去注册中心找接口的实现类
  27. String interfaceName=transferModel.getInterfaceName();
  28. URL url=new URL("localhost",8080);
  29. Class implementClass=RegisterServer.get(url,interfaceName);//根据url和接口名找一个实现类
  30. //然后new出这个实现类,然后执行一下需要调用的这个方法
  31. Method method=implementClass.getMethod(transferModel.getMethodName(),transferModel.getParamTypes());//这里Class的getMethod方法的第一个参数:方法的名字,第二个参数,方法的参数类型
  32. //执行,并保存返回值
  33. String result=(String)method.invoke(implementClass.newInstance(),transferModel.getParams());//第一个参数:new出来的这个实现类,第二个参数:参数 我们这里因为知道sayHello方法返回的是String,所以强转成String了,实际dubbo框架肯定是Object
  34. //然后把结果返回,通过outputstream返回给resp
  35. OutputStream outputStream=resp.getOutputStream();
  36. IOUtils.write(result,outputStream);//把字符串给output了 这样就完成了一个结果的返回
  37. //server端就写完了
  38. } catch (IOException e) {
  39. e.printStackTrace();
  40. } catch (ClassNotFoundException e) {
  41. System.out.println("找不到这个类");
  42. e.printStackTrace();
  43. } catch (NoSuchMethodException e) {
  44. System.out.println("没有这个方法");
  45. e.printStackTrace();
  46. } catch (IllegalAccessException e) {
  47. e.printStackTrace();
  48. } catch (InstantiationException e) {
  49. e.printStackTrace();
  50. } catch (InvocationTargetException e) {
  51. e.printStackTrace();
  52. }
  53. }
  54. }
  1. package org.rico.learnDubbo.protocol.http;
  2. import org.apache.catalina.*;
  3. import org.apache.catalina.connector.Connector;
  4. import org.apache.catalina.core.StandardContext;
  5. import org.apache.catalina.core.StandardEngine;
  6. import org.apache.catalina.core.StandardHost;
  7. import org.apache.catalina.startup.Tomcat;
  8. /**
  9. * Created by Rico on 2018/12/20.
  10. */
  11. public class HttpServer {
  12. public void start(String hostname,Integer port){
  13. Tomcat tomcat=new Tomcat();
  14. Server server=tomcat.getServer();
  15. Service service=server.findService("Tomcat");//默认 叫tomcat
  16. Connector connector=new Connector();
  17. connector.setPort(port);
  18. Engine engine=new StandardEngine();
  19. engine.setDefaultHost(hostname);
  20. Host host=new StandardHost();
  21. host.setName(hostname);
  22. String contextPath="";
  23. Context context=new StandardContext();
  24. context.setPath(contextPath);
  25. context.addLifecycleListener(new Tomcat.FixContextListener());//加一个tomcat生命周期的监听器
  26. host.addChild(context);
  27. engine.addChild(host);
  28. service.setContainer(engine);
  29. service.addConnector(connector);
  30. //tomcat是servlet的容器 所以要加入servlet,servlet用来处理请求的
  31. tomcat.addServlet(contextPath,"dispatcher",new DispatcherServlet());//指定servlet,第二个参数是servlet的名字,第三个参数是指定其实现类
  32. context.addServletMappingDecoded("/*","dispatcher");//mapping
  33. try {
  34. tomcat.start();//只是初始化
  35. tomcat.getServer().await();//接收请求
  36. } catch (LifecycleException e) {
  37. e.printStackTrace();
  38. }
  39. }
  40. }
  1. package org.rico.learnDubbo.protocol.http;
  2. import org.apache.commons.io.IOUtils;
  3. import org.rico.learnDubbo.framework.TransferModel;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.io.ObjectOutputStream;
  7. import java.io.OutputStream;
  8. import java.net.HttpURLConnection;
  9. import java.net.MalformedURLException;
  10. import java.net.ProtocolException;
  11. import java.net.URL;
  12. /**
  13. * Created by Rico on 2018/12/21.
  14. */
  15. public class HttpClient {
  16. public String post(String hostname, Integer port, TransferModel transferModel) {
  17. try {
  18. //发送请求
  19. URL url = new URL("http", hostname, port, "/");
  20. HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
  21. httpURLConnection.setRequestMethod("POST");
  22. httpURLConnection.setDoOutput(true);
  23. OutputStream outputStream = httpURLConnection.getOutputStream();
  24. ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
  25. objectOutputStream.writeObject(transferModel);
  26. objectOutputStream.flush();
  27. objectOutputStream.close();
  28. //发送完请求,然后拿到结果
  29. InputStream inputStream=httpURLConnection.getInputStream();
  30. return IOUtils.toString(inputStream);
  31. } catch (MalformedURLException e) {
  32. e.printStackTrace();
  33. return "";
  34. } catch (ProtocolException e) {
  35. e.printStackTrace();
  36. return "";
  37. } catch (IOException e) {
  38. e.printStackTrace();
  39. return "";
  40. }
  41. }
  42. }

未完,待续….

目录结构

下面2张图帮助理解源码

源码下载

This blog is under a CC BY-NC-SA 3.0 Unported License
本文链接:http://hogwartsrico.github.io/2018/12/20/write-a-dubbo/