dubbo源码学习系列动手写dubbo核心原理(代码片段)

Dream_it_possible! Dream_it_possible!     2023-01-06     691

关键词:

前言

       我觉得通过学习源码,可以获取到与大师交流的机会,优秀的设计能让我在编程思想上得到锻炼提升,也会让我去更注重自己的代码质量 !

一、 Dubbo 架构详解 

      理解Dubbo前,最好先手动画一下dubbo的架构图,画图理解架构是最清晰有效地方式。

各模块的职责:

  • 注册中心:  提供服务发现与注册功能, 如果服务发生变动通过watch机制通知服务消费方。
  • 服务消费者:  服务的调用方,在启动的时候会从注册中心拉取到服务地址列表通过Map缓存到本地。
  • 服务提供者:  服务的提供方,在启动的时候会将服务注册到远程注册中心,例如zookeeper, 同时也本地注册,提供接口方法的实现。
  • 监视器:  监视并统计服务提供者和服务消费者在调用时的一些参数数据。

二、  动手写Dubbo

       在写dubbo前,我们一定要先理清他的实现逻辑,最好画一个流程图,或者是通过顺序罗列出执行顺序,然后再去写代码。

       dubbo源码执行流程分析: Dubbo 源码学习系列(一) 浅析远程调用的核心流程_Dream_it_possible!的博客-CSDN博客_dubbo源码学习     

       我自己写了四个版本, 每个版本都有迭代,后续会继续完善,使用的Java版本是 1.8, 每个版本的实现关键点和步骤如下: 

v1.0 
服务提供者和服务消费者都使用http协议, 服务提供者使用tomcat容器处理请求,服务消费者通过httpClient将请求发送出去。
1. 服务提供者
     服务提供者要做的事情可以总结为如下两点: 
    1)  本地注册到registry, 注册接口名和实现类的Class。
    2)  使用remotemap 替代zookeeper 注册中心,注册接口名和服务地址列表
    3)  使用http 协议启动tomcat容器接收请求,处理请求。
         DispatcherServlet 接收请求-----> HttpServerHandler-----> response。


2. 服务消费者
    1)  使用动态代理模式获取接口的代理对象, 使用代理对象调用目标方法
         通过cglib代理模式生成目标对象的代理对象
            执行invoker()方法,注: invoke()方法在调用目标方法时执行, 不明白的可以先了解动态代理。
                   根据接口名从使用remotemap拿到url列表,然后通过负载均衡策略选一个url进行调用
                     将Url和invocation发送到服务提供者处理。
                         返回result打印调用结果。

v 2.0
   使用zookeeper注册中心缓存服务地址列表。
   1. 服务提供者
       在服务启动时将接口的Class Name(不是实现类的Class)和服务地址列表注册到zookeeper
       
   2. 在invoke()方法里先通过zookeeper 获取到服务地址列表,然后通过负载均衡策略选一个url。

v 3.0 
   实现dubbo协议,使用netty server 来处理请求。
   
v 4.0 
   利用工厂设计模式优化代码结构。

实现原则:

       1. 服务消费者只管接口调用,不管实现细节。

       2. 服务提供者只提供服务实现,在调用的时候才去处理请求。

 版本 v1.0: 

        1. 服务提供者能提供服务,服务消费者能够消费服务。

        2. 使用本地文件替代zookeeper注册中心。

项目目录结构:

 项目依赖:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example.dubbo</groupId>
    <artifactId>dubbo-project</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>dubbo-project</name>
    <description>project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>9.0.45</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
        </dependency>
        <!-- java 工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.5.7</version>
        </dependency>
        <!-- apache common工具包-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>com.openhtmltopdf</groupId>
            <artifactId>openhtmltopdf-core</artifactId>
            <version>0.0.1-RC9</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.13</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

 1. 模拟服务提供者

        本地注册中心

        本地注册的用处是在启动的时候用来缓存,在处理请求的时候会用到,根据接口的全限定名获取到实现类的Class,  当服务消费方把请求的目标接口的方法名和方法参数列表发过来后就可以获取到method对象, 然后通过method对象在服务提供方执行目标方法。

package com.example.dubbo.provider;

import com.example.dubbo.framework.URL;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author bingbing
 * @date 2021/4/29 0029 10:53
 * 本地注册中心
 */
public class LocalRegistry 


    private static Map<String, Class> clazzMap = new HashMap<>();


    public static void regist(String interfacename, Class implClazz) 
        clazzMap.put(interfacename, implClazz);
    

    public static Class getClass(String interfacename) 
        return clazzMap.get(interfacename);
    


         本地模拟zookeeper注册中心

             理解了dubbo的服务消费模块后,我们就知道服务提供者在启动应用时会将本地的接口信息注册到zookeeper注册中心。

             本地可以使用map去替代zookeeper缓存接口的全限定名和服务地址列表,为什么缓存这两个值?  是因为在调用时如果有多实例的情况下,服务消费端调用接口达到负载均衡的效果。

package com.example.dubbo.registry;

import com.example.dubbo.framework.URL;
import com.sun.org.apache.regexp.internal.RE;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author bingbing
 * @date 2021/4/29 0029 10:53
 * 暂时替代远程注册中心 zookeeper
 * 使用map缓存地址列表
 */
public class RemoteRegistry 


    private static Map<String, List<URL>> remotemap = new HashMap<>();

    private static final String filePath = "/temp.text";

    public static void registry(String interfacename, URL url) 
        List<URL> lists = new ArrayList<>();
        if (remotemap == null) 
            remotemap = new HashMap<>();
        
        lists.add(url);
        remotemap.put(interfacename, lists);
        saveFile();
    

    public static List<URL> get(String interfacename) 
        Map<String, List<URL>> map = getFile();
        return map.get(interfacename);
    


    public static void saveFile() 
        File file = new File(filePath);
        if (!file.exists()) 
            try 
                file.createNewFile();
             catch (IOException e) 
                e.printStackTrace();
            
        
        // 将对象序列化后保存到文件里
        try 
            FileOutputStream fos = new FileOutputStream(filePath);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(remotemap);
         catch (FileNotFoundException e) 
            e.printStackTrace();
         catch (IOException e) 
            e.printStackTrace();
        
    

    // 从文件中读取
    public static Map<String, List<URL>> getFile() 
        try 
            FileInputStream fis = new FileInputStream(filePath);
            ObjectInputStream ois = new ObjectInputStream(fis);
            Object obj = ois.readObject();
            return (Map<String, List<URL>>) obj;
         catch (FileNotFoundException e) 
            e.printStackTrace();
         catch (IOException e) 
            e.printStackTrace();
         catch (ClassNotFoundException e) 
            e.printStackTrace();
        
        return null;
    


     注:   此处有坑!

         坑一: 

               我在invoke()方法里获取到服务地址列表时, List<URL> lists = RemoteRegistry.get(interfaceclass.getName());  从RemoteRegistry获取到的lists 值竟然为null,我明明在服务提供者写了启动时自动将服务地址列表注册到 RemoteRegistry呀! 然后我找到原因,因为两个不同的应用是不能直接通信的,相当于两个不同的环境,每个应用的RemoteRegistry是独立的,所以拿不到服务提供者的map。

       解决方法: 

               在注册时,将map写入到文件里,服务消费者在调用的时, 每次get前去拿getFile(), 这样数据就能达到共享的目的了!

       坑二:

               将map对象在写入到文件时报错: URL不能被序列化。

      解决方法:

               继承Serializable 接口并添加唯一标识。

            

              

    基于Http协议设置tomcat启动相关参数

           设置一个tomcat容器,作为请求处理的载体,另外需要一个DispatcherServlet接收和分发请求,写好后执行一下main方法,看能不能正常启动, 可以在启动完成后,访问localhost:8080。

package com.example.dubbo.protocol.http;

import com.example.dubbo.framework.URL;
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 bingbing
 * @date 2021/4/29 0029 11:00
 */
public class HttpServer 


    public void start(URL url) 
        Tomcat tomcat = new Tomcat();
        Server server = tomcat.getServer();
        Service service = server.findService("Tomcat");

        Connector connector = new Connector();
        connector.setPort(url.getPort());


        Engine engine = new StandardEngine();
        engine.setDefaultHost(url.getHost());


        Host host = new StandardHost();
        host.setName(url.getHost());
        String contextpah = "";


        Context context = new StandardContext();

        context.setPath(contextpah);
        context.addLifecycleListener(new Tomcat.FixContextListener());

        host.addChild(context);
        engine.addChild(host);

        service.setContainer(engine);
        service.addConnector(connector);

        //配置dispatcherServlet 来处理请求
        tomcat.addServlet(contextpah, "dispatcher", new DispatcherServlet());
        // 配置mapping
        context.addServletMappingDecoded("/*", "dispatcher");
        try 
            tomcat.start();
            tomcat.getServer().await();
         catch (Exception e) 
            e.printStackTrace();
        
    


    public static void main(String[] args) 
        URL url = new URL("localhost", 8080);
        HttpServer server = new HttpServer();
        server.start(url);
    

      DispatcherServlet

         分发并处理请求

package com.example.dubbo.protocol.http;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author bingbing
 * @date 2021/4/29 0029 11:00
 */
public class DispatcherServlet extends HttpServlet 

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
        new HttpServerHandler().handler(req, resp);
    

       HttpServerHandler,  万事具备,只欠东风! 在此方法里method对象通过反射执行目标接口方法。

package com.example.dubbo.protocol.http;

import com.alibaba.fastjson.JSONObject;
import com.example.dubbo.framework.Invocation;
import com.example.dubbo.provider.LocalRegistry;
import com.example.dubbo.utils.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

/**
 * @author bingbing
 * @date 2021/4/29 0029 11:00
 */
public class HttpServerHandler 

    Logger logger = LoggerFactory.getLogger(HttpServerHandler.class);

    /**
     * 处理请求,解析invocation对象
     *
     * @param req
     * @param resp
     */
    public void handler(HttpServletRequest req, HttpServletResponse resp) 
        try 
            logger.debug("收到一个请求,开始处理....");
            // 1. 反序列化,解析对象
            Invocation invocation = JSONObject.parseObject(req.getInputStream(), Invocation.class);
//            invocation.setParamTypes(new Class[]String.class);
            logger.debug("接收到invocation", invocation.toString());
            // 2. 根据接口名获取到接口实现类的Class
            Class impl = LocalRegistry.getClass(invocation.getInterfaceName());
            // 3. 获取反射调用的method对象, 通过方法名和参数列表类型获取方法method对象
            Method method = impl.getMethod(invocation.getMethodName(), invocation.getParamTypes());
            // 4. 执行方法调用
            Object obj = method.invoke(impl.newInstance(), invocation.getParams());
            logger.debug("返回结果:", obj);
            resp.setCharacterEncoding("utf-8");
            resp.setContentType("*/*;charset=UTF-8");
            IOUtils.write(obj, resp.getOutputStream());
         catch (IOException e) 
            e.printStackTrace();
         catch (NoSuchMethodException e) 
            e.printStackTrace();
         catch (IllegalAccessException e) 
            e.printStackTrace();
         catch (InstantiationException e) 
            e.printStackTrace();
         catch (InvocationTargetException e) 
            e.printStackTrace();
        
    


  2. 测试服务提供者

      为什么要测试服务提供者?

    1.   因为在服务消费端最终会把invocation对象发送给服务提供者,服务提供者会根据相应的协议去接收并处理请求。

     2.  写好服务提供者后,首先使用postman测一下看能不能获取到数据,如果不能就先检查一下代码是否写的有问题。

     

          postman测试技巧: 

            1)  将参数指定为invocation对象对应的属性值。

            2)  接口名为接口所在的全限定名,即所在包名路径.接口名

            3)  参数类型的Class 用java.lang.String 字符串。


    "interfaceName": "com.example.dubbo.provider.api.UserInterface",
    "methodName": "sayHello",
    "paramTypes": [
        "java.lang.String"
    ],
    "params": [
        "bingbing"
    ]

      

              

    服务提供者可以调通后, 就可以开始写服务消费者了! 

3. 模拟服务消费者

           消费方不管实现,只知道接口即可,屏蔽实现细节,因此在调用的接口的时候应该达到尽可能地精简, 通过代理工厂,达到只需要传接口的Class即可获取到代理对象,然后调用目标方法传递参数即可!

package com.example.dubbo.consumer;

import com.example.dubbo.framework.ProxyFactory;
import com.example.dubbo.provider.api.UserInterface;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author bingbing
 * @date 2021/4/29 0029 10:17
 */
public class ConsumerApplication 

    public static Logger logger = LoggerFactory.getLogger(ConsumerApplication.class);

    public static void main(String[] args) 
        // 消费方不管实现,只知道接口即可,屏蔽实现细节
        UserInterface userInterface = ProxyFactory.getProxy(UserInterface.class);
        while (true) 
            try 
                Thread.sleep(1000);
             catch (InterruptedException e) 
                e.printStackTrace();
            
            String result = userInterface.sayHello("bingbing");
            System.out.println("执行成功,返回结果:" + result);
        

    

          如果你还不了解动态代理,那么可以先补一下cglib动态代理和jdk动态代理模式。

          画个图分析一下执行流程:

       

newInvocationHandler的invoke()方法执行消费方完整的流程, 代码如下: 

package com.example.dubbo.framework;

import com.example.dubbo.protocol.http.HttpClient;
import com.example.dubbo.provider.LocalRegistry;
import com.example.dubbo.registry.RemoteRegistry;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.cglib.proxy.Proxy;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Random;

/**
 * @author bingbing
 * @date 2021/4/29 0029 10:46
 */
public class ProxyFactory<T> 


    public static <T> T getProxy(final Class interfaceclass) 

        return (T) Proxy.newProxyInstance(interfaceclass.getClassLoader(), new Class[]interfaceclass, new InvocationHandler() 
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable 
                //  可以自己定义mock, 通过Mock实现服务降级

                // 2. 获取服务地址列表
                List<URL> lists = RemoteRegistry.get(interfaceclass.getName());
                // 3. 负载均衡策略选择一个url进行使用。
                URL url = LoadBalance.random(lists);
                // 3. 发送http 请求
                HttpClient client = new HttpClient();
                Invocation invocation = new Invocation(interfaceclass.getName(), method.getName(), objects, method.getParameterTypes());
                Object obj = client.send(url, invocation);
                return obj;
            
        );
    


最终实现将请求发送给服务提供者的地方是Object obj = client.send(url, invocation);

   借用 apache的工具包下的DefaultHttpClient发送post请求,因为dubbo调用的方式只有post请求,因此我们也只需要用post请求方式即可。

package com.example.dubbo.protocol.http;

import com.alibaba.fastjson.JSONObject;
import com.example.dubbo.framework.Invocation;
import com.example.dubbo.framework.URL;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

/**
 * @author bingbing
 * @date 2021/4/29 0029 11:00
 */
public class HttpClient 


    public Object send(URL url, Invocation invocation) 

        // 1.将invocation对象序列化转换成json对象
        // 2. 通过post方式发起http请求。
        String jsonInvocation = JSONObject.toJSONString(invocation);

        // 3. 获取响应结果并返回。
        String urlDetail = url.getHost() + ":" + url.getPort();
        try 
            return doPostData(urlDetail, jsonInvocation);
         catch (Exception e) 
            e.printStackTrace();
        
        return null;
    

    public static Object doPostData(String url, String json) throws Exception 
        DefaultHttpClient client = new DefaultHttpClient();
        HttpPost post = new HttpPost("http://" + url);
        String result = "";
        HttpResponse res = null;
        try 
            StringEntity s = new StringEntity(json, "UTF-8");
            s.setContentType("application/json");
            post.setHeader("Accept", "application/json");
            post.setHeader("Content-type", "application/json; charset=utf-8");
            post.setEntity(s);
            res = client.execute(post);
            if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) 
                result = EntityUtils.toString(res.getEntity());
                return result;
            
         catch (Exception e) 
            if (res == null) 
                return "HttpResponse 为 null!";
            
            throw new RuntimeException(e);
        
        if (res == null || res.getStatusLine() == null) 
            return "无响应";
        
        return result;
    


写好后

   先启动服务提供者,再启动服务消费者

       服务提供者控制台:

       服务消费者控制台: 

4. 总结 

        v1.0版本实现了服务消费者能够调用服务提供者的目标接口方法,通过文件实现共享服务地址列表。

5. 源码地址

       dubbo-rpc: 手写dubbo仓库源码

dubbo源码分析-从xml到我们认识的java对象

...希望能够了解dubbo的底层实现,这半年来一直在看dubbo的源码,有点断断续续的,于是准备写一个dubbo源码系列的分析文章,一来方便自己总结,二来也能够让自己的学习有输出分享。  整个系列会从dubbo的xml到bean到生产者启动... 查看详情

dubbo源码分析系列-服务的发布

RPC简化类图RPC模块核心接口和抽象实现默认实现Dubbo协议的接口和抽象实现服务发布过程调用过程上图是服务提供者暴露服务的主过程:首先ServiceConfig类拿到对外提供服务的实际类ref(如:HelloWorldImpl),然后通过ProxyFactory类的getInvo... 查看详情

dubbo系列dubbo的核心技术--rpc调用

dubbo的核心技术--RPC调用:分为俩部分RPC协议Protocol和方法调用Invoke;一、RPC协议Protocol(RemoteProcedureCall)远程过程调用协议1、我们平时使用最多的http协议其实也属于RPC协议,下图分别是普通的传输层TCP和应用层http与dubbo优化后... 查看详情

dubbo源码实践-开篇

最近有点时间,想学习一下dubbo2.7的源码。推荐源码的学习资料:00开篇词深入掌握Dubbo原理与实现,提升你的职场竞争力-打工人技术合集该资料在Bilibili站上还有对应的学习视频。比较赞!!!网上的很多... 查看详情

源码分析dubbo专栏

本系列文章主要针对Dubbo2.6.2(dubbox2.8.4)版本,从源码的角度分析Dubbo内部的实现细节,加深对Dubbo的各配置参数底层实现原理的理解,更好的指导Dubbo实践,其目录如下:1、源码分析Dubbo前置篇-寻找注册中心、... 查看详情

dubbo源码学习:spring自定义标签

做dubbo的配置时很容易发现,dubbo有一套自己的标签,提供给开发者配置,其实每一个标签对应着一个实体,在容器启动的时候,dubbo会对所有的配置进行解析然后将解析后的内容设置到实体里,最终dubbo会根据实体中的值生成贯... 查看详情

dubbo(一)——dubbo集成于spring的原理

参考技术A最近一直在看dubbo的源码部分。在阅读的时候,需要有一个入手点,才能一点一点的进行下去。自己在研究的时候,发现思绪比较乱,于是就以芋道源码为基础,一点一点的啃食。芋道源码是直接从dubbo的配置和一些核... 查看详情

源码分析dubbo专栏

本系列文章主要针对Dubbo2.6.2(dubbox2.8.4)版本,从源码的角度分析Dubbo内部的实现细节,加深对Dubbo的各配置参数底层实现原理的理解,更好的指导Dubbo实践,其目录如下:1、源码分析Dubbo前置篇-寻找注册中心、... 查看详情

dubbo原理应用与面经总结(代码片段)

  研读dubbo源码已经有一段时间了,dubbo中有非常多优秀的设计模式和示例代码值得学习,但是dubbo的调用层级和方法链都较为繁杂,如果不对源码思路进行梳理则很容易忘却,因此总结一篇研读心得,从阅读源码的思路、... 查看详情

dubbo源码学习scopebeanfactory对比spring的beanfactory(代码片段)

目录1.ScopeBeanFactory与BeanFactory对比2.注册Bean3.执行一系列的PostProccessor1.ScopeBeanFactory与BeanFactory对比        ScopeBeanFactory是Dubbo自己定义的管理Bean的一个类,他可与ScopeModel一起实现应用和模块之间的数据共享等功能,ScopeBeanF... 查看详情

dubbo源码学习scopebeanfactory对比spring的beanfactory(代码片段)

目录1.ScopeBeanFactory与BeanFactory对比2.注册Bean3.设置Aware和执行一系列的PostProccessor1.ScopeBeanFactory与BeanFactory对比        ScopeBeanFactory是Dubbo自己定义的管理Bean的一个类,他可与ScopeModel一起实现应用和模块之间的数据隔离和共享等... 查看详情

dubbo源码分析系列-扩展机制的实现

Spring可扩展Schema像标签dubbo:monitor、dubbo:service、dubbo:provider等怎么读的,读完之后怎么又是怎么解析的呢?以上标签都是基于Spring可扩展Schema提供的自定义配置下面举个例子1)创建JavaBean首先设计好配置项,通过JavaBean来建模,如... 查看详情

dubbo学习——dubbo原理

RPC原理一次完整的RPC调用流程(同步调用,异步另说)如下:1)服务消费方(client)调用以本地调用方式调用服务;2)clientstub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息... 查看详情

dubbo学习记录--spring整合dubbo中@reference注解解析原理

Spring整合Dubbo中@Reference注解解析原理@Reference:可以用在属性或者方法,意味着需要引用某个Dubbo服务,那么Dubbo整合Spring后,我很好奇怎么把这个过程完成的。packageorg.apache.dubbo.demo.provider;publicclassApplicationpub 查看详情

深入浅出dubbo3原理及实战「新特性简介」dubbo3新特性概览的介绍说明

Dubbo3的微服务框架系列本系列专题是关于Dubbo的简单介绍,涵盖Dubbo的核心概念、基本使用方式以及Dubbo3核心功能。Dubbo的基本介绍ApacheDubbo是一款微服务开发框架,它提供了RPC通信与微服务治理两大关键能力。使用Dubbo开... 查看详情

dubbo基本原理和用法讲解(代码片段)

...一个实际案例运用dubbo技术,给出一个Demo演示并贴出源码。一、Dubbo是什么?Dubbo是由阿里巴巴开源的RPC服务开发框架。RPC全称是Remoteprocedurecall,即远程过程调用。使得调用远程的程序服务像在本地调用一样。rpc可以... 查看详情

dubbo源码与spring一起学习dubbo里的aware(代码片段)

目录一、Spring1.BeanNameAware2.BeanClassLoaderAware3.ApplicationContextAware4.EnvironmentAware5.ApplicationEventPublisherAware6.aware注入时机二、Dubbo1.ExtensionAccessorAware三、小结    现在很多同行做java开发几年了,被迫停留 查看详情

dubbo源码与spring一起学习dubbo里的aware(代码片段)

目录一、Spring1.BeanNameAware2.BeanClassLoaderAware3.ApplicationContextAware4.EnvironmentAware5.ApplicationEventPublisherAware6.aware注入时机二、Dubbo1.ExtensionAccessorAware三、小结    现在很多同行做java开发几年了,被迫停留 查看详情