hm视频还是有点粗…源码分析跟没讲一样 要学深入的话还是买书吧

Dubbo高可用

服务路由

服务路由包含一条路由规则,路由规则决定了服务消费者的调用目标,即规定了服务消费者可调用哪些服务提供者,Dubbo提供三种服务路由实现,分别为条件路由ConditionRouter、脚本路由ScriptRouter、标签路由TagRouter

条件路由规则的格式:【服务消费者匹配条件】=>【服务提供者匹配条件】
例如host=10.20.153.10=>host=10.20.153.11表示IP为10.20.153.10的服务消费者只可以调用IP为10.20.153.11机器上的服务,不能调用其他机器的服务。
如果服务消费者的匹配条件为空,表示不对服务消费者进行限制。如果服务提供者的匹配条件为空,表示对某些服务消费者禁用服务。

配置举例:
白名单:
host!=10.20.153.10=>
黑名单:
host=10.20.153.10=>
读写分离:
method=find,list,get,is=>172.22.3.94,172.22.3.95,172.22.3.96
method!=find,list,get,is=>172.22.3.97
前后台分离:
application=front=>host=172.3.22.91,172.3.22.92
application!=front=>host=172.3.22.94,172.3.22.95


集群容错

  • Failover Cluster
    失败自动切换,当失败后会重连其他服务器,是默认策略。通常用于读操作,但重试会带来更长延迟,可通过retries=2来设置重试次数。
  • Failfast Cluster
    快速失败,只发起一次调用,失败立即报错。通常用于非幂等性写操作,例如新增记录。
  • Failsafe Cluster
    失败安全,出现异常时,直接忽略,通常用于写入日志等操作。
  • Failback Cluster
    失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知等操作。
  • Forking Cluster
    并行调用,只要有一个请求成功即返回。通常用于实时性要求比较高的读操作,但需要消耗更多服务资源。可通过forks=2设置最大并行数。
  • Broadcast Cluster
    广播调用所有服务提供者,依次逐个调用,任意一台报错则报错。通常用于通知所有服务提供者更新缓存或日志等本地资源信息。

负载均衡

  • Random LoadBalance
    默认值,随机负载均衡,按照权重设置随机概率,无状态
  • RoundRobin LoadBalance
    轮询负载均衡,可能会导致请求累积的问题。
    例如有三台机器,一三速度较快,第二台机器比较慢,当请求调到第二台时就卡在那,一定时间后所有请求都卡在第二台上。
  • LeastActive LoadBalance
    使活跃数最少的机器处理请求,如果活跃数相同则随机。目的是让处理能力弱的机器接收到更少的请求,每个服务维护一个活跃数计数器,处理请求时计数器加1,完成时减1。
    例如A机器开始处理请求,该计数器加1,此时A还未处理完成,而B机器接受到请求后很快处理完毕。此时A、B的活跃数分别是1,0。当又产生了一个新的请求,则选择B机器去执行(B活跃数最小),这样使处理慢的机器A收到少的请求。目的是让处理能力弱的机器接收到更少的请求
  • ConsistentHash LoadBalance
    一致性哈希,使相同参数的请求总发送给同一台机器。

服务降级

使用Dubbo进行服务调用时,可能由于服务器宕机、网络超时、并发数太高等原因出现RpcException,调用失败。
服务降级就是指在由于非业务异常导致服务不可用时,可以返回默认值,避免异常影响到主业务。

环境搭建

创建dubbo父工程以及三个子工程,分别作为服务消费方,服务接口,服务提供方。
注意服务消费方和服务提供方的打包方式设置为war,然后在src/main下创建webapp目录并设为web资源。

父工程的pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache/POM/4.0.0"
         xmlns:xsi="http://www.w3/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache/POM/4.0.0 http://maven.apache/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>dubbo</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>dubbo_provider</module>
        <module>dubbo_consumer</module>
        <module>dubbo_interface</module>
    </modules>

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

编写服务提供方
pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache/POM/4.0.0"
         xmlns:xsi="http://www.w3/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache/POM/4.0.0 http://maven.apache/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>dubbo</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <packaging>war</packaging>
    <artifactId>dubbo_provider</artifactId>

    <dependencies>
        <!-- spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>

        <!-- dubbo -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.14</version>
        </dependency>
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>
        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.12.1.GA</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
        </dependency>

        <dependency>
            <groupId>org.example</groupId>
            <artifactId>dubbo_interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <configuration>
                    <port>8083</port>
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

在resources目录下增加配置文件
分别是dubbo的配置文件和日志信息打印文件

dubbo配置文件,zookeeper配置为zookeeper://虚拟机ip:端口号,可以参考之前zookeeper的文章

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework/schema/beans"
       xmlns:xsi="http://www.w3/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework/schema/p"
       xmlns:context="http://www.springframework/schema/context"
       xmlns:dubbo="http://code.alibabatech/schema/dubbo"
       xmlns:mvc="http://www.springframework/schema/mvc"
       xmlns:tx="http://www.springframework/schema/tx"
       xsi:schemaLocation="http://www.springframework/schema/beans
                           http://www.springframework/schema/beans/spring-beans.xsd
                           http://www.springframework/schema/mvc
                           http://www.springframework/schema/mvc/spring-mvc.xsd
                           http://code.alibabatech/schema/dubbo
                           http://code.alibabatech/schema/dubbo/dubbo.xsd
                           http://www.springframework/schema/context
                           http://www.springframework/schema/context/spring-context.xsd
                           http://www.springframework/schema/tx
                           http://www.springframework/schema/tx/spring-tx.xsd">

    <!-- 每个dubbo应用(服务提供方和消费方)都必须指定一个唯一名称 -->
    <dubbo:application name="dubbo_provider"/>

    <!-- 指定服务的注册中心 -->
    <dubbo:registry address="zookeeper://192.168.2.142:2181/"/>

    <!-- 配置协议和端口 -->
    <dubbo:protocol name="dubbo" port="20881"/>

    <!-- 指定包扫描 用于发布dubbo服务 -->
    <dubbo:annotation package="com.sjh.service.impl"/>





</beans>

log4j配置文件

log4j.rootLogger=debug,stdout


log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c {1}:%L - %m%n




log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:\\mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c {1}:%L - %m%n

在接口子工程编写服务接口

public interface HelloService {

    String sayHello();

}

在服务提供方编写服务接口实现类

@Service
public class HelloServiceImpl implements HelloService {

    @Override
    public String sayHello() {
        return "dubbo服务被成功调用了";
    }
}


install父工程


编写服务消费方
pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache/POM/4.0.0"
         xmlns:xsi="http://www.w3/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache/POM/4.0.0 http://maven.apache/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>dubbo</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <packaging>war</packaging>
    <artifactId>dubbo_consumer</artifactId>

    <dependencies>
        <!-- spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>

        <!-- dubbo -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.14</version>
        </dependency>
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>
        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.12.1.GA</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
        </dependency>

        <dependency>
            <groupId>org.example</groupId>
            <artifactId>dubbo_interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <configuration>
                    <port>8082</port>
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

编写Controller

@Controller
@RequestMapping("/hello")
public class HelloController {

    @Reference
    private HelloService helloService;

    @RequestMapping(value = "/sayHello",produces = "text/html;charset=UTF-8")
    @ResponseBody
    public String sayHello(){
        //完成对服务的远程调用
        String s = helloService.sayHello();
        System.out.println(s);
        return s;
    }
}

将服务提供方的两个配置文件复制到服务消费方,要做部分修改


在web.xml配置前端控制器

	<!-- 配置前端控制器 -->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext-service.xml</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

再次install父工程


测试
启动服务提供子工程的tomcat


启动服务消费子工程的tomcat


访问localhost:8082/hello/sayHello.do,成功~
8082是消费子工程pom文件里设置的端口,hello/sayHello是controlller配置的路径,.do是拦截方式


配置服务降级

使用mock配置实现服务降级,mock只在出现非业务异常(超时、网络异常)时执行。

mock的配置支持两种,一种为boolean值,默认为false,如果配置为true则默认使用对应mock类,即类名+Mock后缀;另一种配置是return null,可以直接忽略掉异常。mock配置在服务消费方,服务降级不需要对服务提供方配置产生修改。

使用return null

修改服务消费方的配置属性

不开启服务提供方,只启动服务消费方,访问网页,调用方依然正常运行,只是结果为null。


实现mock接口方式

上面return null的方式会对所有方法做统一处理,如果我们想针对不同方法,可以将值设为true,然后实现Mock接口,类名需要使用接口名+Mock后缀,此时如果调用失败就会自动调用该实现类,注意必须要保证有无参构造器。

先修改配置属性为true

之后在接口子工程下创建一个服务接口的实现类,并且再次install父工程。

然后不开启服务提供方,再次运行服务消费方,在网页访问服务路径,观察控制台输出,可以发现成功调用了HelloServiceMock的方法。


整合Hystrix

Hystrix旨在通过控制那些访问远程系统、服务和第三方库的结点,从而对延迟和故障提供更强大的容错能力。Hystrix具备有回退机制和断路器功能的线程和信号隔离,请求缓存和请求打包,以及监控和配置等功能。

①springboot官方提供了对hystrix的集成,直接在pom.xml加入依赖即可。
②在主程序类上增加注解@EnableHystrix来开启功能
③在服务提供者Provider添加@HystrixCommand注解,这样调用会经过Hystrix代理
④在服务消费者Consumer添加@HystrixCommand注解并指定出错时的回调方法fallbackMethod,这样调用出错时会调用fallbackMethod中的方法。


Dubbo线程IO模型

Dubbo采用的是NIO模型。

BIO

同步阻塞,每个客户端连接过来后,服务端都会启动一个线程去处理该客户端的请求。
每个连接都需要一个线程来维护,对应一个while死循环,死循环的目的是为了不断检测该连接上是否有数据可以读,在高并发情况下会浪费大量资源。

NIO

同步非阻塞,新的连接不再创建一个新的线程处理,直接将该连接绑到某个固定的线程,然后这条连接所有的读写都由这个线程来负责。
NIO中只有一个while死循环,该死循环由一个线程控制,这就是NIO中Selector的作用,一条连接来了后直接将其注册到选择器,通过检查选择器就可以批量检查出有数据可读的连接从而读取数据。


例如餐厅中有100个客人,BIO相当于为每一个客人分配一个服务员提供服务,服务员就在客人旁边随时准备提供服务,这就是BIO,一个连接对应一个线程;NIO相当于只有一个服务员,他隔段时间来询问所有的客人然后依次处理请求,这就是NIO模型,所有连接都注册到一个线程。


Dubbo原理图

图👈半部分表示服务消费者Consumer,👆往👇的三层Biz、RPC、Remoting表示业务层、RPC层、远程运输层。

图👉半部分表示服务提供者Provider,👆往👇的前两层UserAPI、后七层ContributorSPI表示面向用户的API和面向扩展者的SPI。

紫色的线表示实现/继承、蓝色虚线表示服务注册/订阅过程、红色的线表示整个RPC的调用过程、黑色的线表示依赖。



Dubbo SPI

SPI为Service Provider Interface,是一种服务发现机制。SPI的本质是将接口实现类的全限定类名配置在文件中,并由服务加载器读取配置文件加载实现类。这样可以在运行时动态把接口替换成实现类,因此可以实现接口和实现类的解耦,提高了程序可扩展性。Dubbo就是通过SPI机制加载所有组件,但Dubbo并未使用Java原生的SPI机制,而是对其进行了增强,使其更好满足需求。在Dubbo中,SPI是一个非常重要的机制。

Java SPI

创建一个maven工程,编写接口以及两个实现类

public interface IService {

    void service();
}
public class ServiceImplA implements IService {

    public void service() {
        System.out.println("实现类A执行了service方法");
    }
}
public class ServiceImplB implements IService {

    public void service() {
        System.out.println("实现类B执行了service方法");
    }
}

在resources目录下新建一个META-INF目录,再创建一个services目录(注意结尾有s),然后创建一个文件,文件名是接口的全限定名,内容是接口实现类的全限定名。


创建测试类

public class SpiTest {

    public static void main(String[] args) {
        ServiceLoader<IService> loader = ServiceLoader.load(IService.class);
        Iterator<IService> iterator = loader.iterator();
        while(iterator.hasNext()){
            //获取具体的实现类
            IService service = iterator.next();
            //执行实现类方法
            service.service();
        }
    }
}

结果:


JavaSPI存在的问题
①配置文件中配置的所有接口实现类无论是否使用都会通过反射进行实例化
当我们运行时,所有的实现类方法都执行了,说明只要在配置文件中进行了配置,不管是否使用都会进行实例化。
②无法根据参数来获取某个指定的实现类
会将全部实现类实例化,除非在配置文件中只配置某一个实现类。


Dubbo SPI

Dubbo重新实现了一套功能更强的SPI机制,Dubbo SPI的相关逻辑封装在ExtensionLoader类中,通过ExtensionLoader可以加载指定的实现类。Dubbo SPI所需的配置文件需要放置在METF-INF/dubbo路径下。
与Java SPI实现类配置不同,Dubbo SPI使用键值对的形式进行配置,这样可以按需求指定实现类。在测试时还需要再接口上标记@SPI注解。

配置文件

在pom.xml引入dubbo依赖,网课真的坑,直接使用注解…

<dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.0</version>
        </dependency>
    </dependencies>

然后给接口添加@SPI注解

编写测试类


public class DubboSpiTest {

    public static void main(String[] args) {
        ExtensionLoader<IService> loader = ExtensionLoader.getExtensionLoader(IService.class);
        Scanner scanner = new Scanner(System.in);
        System.out.println("输入你想实例化的实现类");
        String s=scanner.nextLine();
        loader.getExtension(s).service();
    }
}

运行,输入a会执行实现类A的方法


一开始调用了getExtensionLoader来获取一个对应接口的loader实例,如果接口为空,或者不是一个接口,或者没有加SPI注解都会抛出异常。
如果是接口,将会先从缓存中取值,如果有直接return,没有就new一个新的实例。

之后调用接口loader实例的getExtension方法通过我们配置文件指定的key值来获取具体的实现类,如果是空会抛出异常,否则还是先从缓存中取值,如果没有要放到缓存里,然后获取一个holder实例,再通过holder实例来获取接口的实现类实例,如果是第一次获取会为空,需要再使用createExtension方法来创建具体的实例。这里使用了双重锁机制保证线程安全。

createExtension使用反射机制来创建该接口的实现类的实例对象。
先通过getExtensionClasses获取所有的实现类Class对象,该结果是一个map集合,键是配置文件的key值,值是对应的实现类Class对象,然后再通过name获取指定的实现类Class对象,还是先从缓存中取值,如果没有的话就通过反射来创建实例对象。
创建完成后通过injectExtension来为实例进行依赖注入,原理:Dubbo通过反射获取到实例的所有方法,然后遍历方法列表,检测其是否具有setter特征,如有则通过ObjectFactory获取依赖对象,最后通过反射调用setter方法将依赖注入到目标对象。
最后循环创建wrapper实例,将当前实现类实例作为参数传递给wrapper的构造器,通过反射创建wrapper实例,注入依赖然后将wrapper实例再次赋值给instace。


通过getExtensionClasses获取所有的实现类Class对象

通过injectExtension来为实例进行依赖注入


Dubbo 服务暴露

Spring容器启动时会通过BeanDefinitionParser来解析配置文件

Dubbo的配置文件加载依赖实现类DubboBeanDefinitionParser,它会将配置文件中不同的标签解析成不同的xxxConfig

在解析之前,会先执行DubboNamespaceHandler的init方法
方法中的elementName就对应dubbo配置文件中的标签属性


如果是dubbo:service标签,会解析成ServiceBean

ServiceBean中实现了InitializingBean、 ApplicationListener接口,在afterPropertiesSet方法中主要讲配置文件中的属性依次配置到对应的bean,在spring上下文刷新事件后会回调onApplicationEvent方法。

onApplicationEvent的export方法讲服务暴露导出

export调用了父类ServiceConfig的export中的doExport方法,检查延迟和是否导出,最后执行doExportUrls方法

doExportUrls()首先通过loadRegistries加载注册中心连接,然后遍历ProtocolConfig集合导出每个服务,并在导出服务的过程中,将服务注册到注册中心。doExportUrlsFor1Protocol主要将版本、时间戳、方法名以及各种配置对象的字段信息放入到map中,map中的内容将作为URL的查询字符串。构建好map后,紧接着是获取上下文路径、主机名以及端口号等信息,最后将map和主机名等数据传给URL构造器创建URL对象。

无论是导出到本地还hi远程都需要Invoker对象,Invoker是ProxyFactory代理工厂创建的对象,invoke封装了调用实体。根据scope的参数决定导出服务到本地还是远程。如果scope是none则不处理,如果不是remote则导出本地,如果不是loacl则导出远程。导出到远程包括了服务导出和服务注册两个过程。dubbo服务实例默认使用NettyServer,服务注册调用getRegister方法创建连接注册中心,调用register方法注册服务,如果是zookeeper做注册中心,调用zookeeper客户端创建服务节点,服务注册成功,在ZooInspector可以查看注册服务的结点数据。


Dubbo 服务引入

Dubbo服务引入时机有两个,第一个是在spring容器调用ReferenceBean的afyerPropertiesSet方法时引用服务,第二个是在ReferenceBean对应的服务被注入到其它类中时引用。这两个引用服务时机的区别在于,第一个是饿汉式的,第二个是懒汉式的。默认情况下Dubbo使用懒汉式引用服务,如果需要改为饿汉式,可以通过配置dubbo:reference的init属性开启。

当我们的服务被注入到其他类时,Spring会第一时间调用ReferenceBean的getObject方法,并由该方法执行服务引用逻辑。

在进行具体工作之前需要先进行配置检查与收集工作,接着根据收集到的信息决定服务引用的方式,有三种,第一种是引用本地(JVM)服务,第二种是通过直连方式引用远程服务,第三是通过注册中心引用远程服务,不管是哪一种方式最终都会得到一个Invoker实例。如果有多个注册中心,多个服务提供者,这个时候就会得到一组Invoker实例,此时需要通过集群管理类Cluster将多个Invoker合并成一个实例。合并后的Invoker实例已经具备了调用本地或远程服务的能力了,但并不能暴露给用户使用,这样会对用户业务代码造成侵入。此时框架还需要通过代理工厂类ProxyFactory为服务接口生成代理类,并让代理类去调用Invoker逻辑,避免了Dubbo框架对业务代码的侵入。

服务引用的入口是ReferenceBean的getObject方法,该方法定义在Spring的FactoryBean接口中


配置解析逻辑封装在init方法中,最终要调用createProxy创建代理对象,创建对象的同时也会调用其他方法构建以及合并Invoker实例。
Invoker是Dubbo的核心模型,代表一个可执行体。在服务提供方Invoker用来调用服务提供类,在服务消费方用于执行远程调用,Invoker是由Protocol的实现类DubboProtocol调用refer方法。
Dubbo使用NettyClient进行通信,根据connections的连接数量决定是获取共享客户端还是创建新的客户端实例,默认情况下使用共享客户端实例。

更多推荐

【菜鸟教程】Dubbo基础入门下——Dubbo的入门案例