总结dubbo知识点

一、dubbo特性介绍

配置说明

配置优先级

  • 方法级别>服务级别>应用级别
  • 级别一样的情况下,消费者端的配置优先

超时配置

consumer端三个级别都有超时配置

dubbo.method > dubbo.reference > dubbo.consumer

同时,provider端也有超时配置

dubbo.method>dubbo:service>dubbo:provider

重试次数配置

consumer端及provider端的三个级别配置中都有重试次数retries配置,这个重试次数不包括第一次调用,没有配置的话,客户端默认第一次调用失败之后会重试2次,也就是一共3次调用

设置retries=0则不重试

对于一些需要幂等的操作(通常是query/update/delete操作)可以设置重试次数,对于一些非幂等性质的操作(例如insert操作)不可以设置重试次数,配置retries=0来关闭重试

多版本配置

consumer端配置version=”*“的方式可以随机调用新老版本的provider

本地存根

远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑,比如:做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 API 中带上 Stub,客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub,然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy。

启动检查配置

默认客户端启动前必须依赖的服务端先启动,也可以设置check=false不强制检查,客户端运行时调用服务端发现没有服务启动时才报错

通过dubbo.consumer可以给客户端设置统一的默认属性,比如check,timeout

负载均衡配置

  • random(默认)

    可以设置weight

  • roundrobin

    可以设置weight

  • leastactive
  • consistenthash

Dubbo 的负载均衡策略:一致性哈希策略

配置对哪些参数做哈希计算,默认是只对第一个参数

配置需要多少份虚拟节点,也就是一个提供服务的实例需要冗余多少份,默认是160份虚拟节点

参考:一致性哈希策略

设置weight的方式:

  • provider端通过dubbo:service来设置,或dubbo:method
  • consumer端通过dubbo:reference来设置,或dubbo:method
  • 在dubbo-admin中动态调整weight,推荐方式

多协议配置

默认dubbo协议,dubbo协议建议数据包100k以内

接口异步调用

服务降级

  • mock=force:return+null 表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。
  • mock=fail:return+null 表示消费方对该服务的方法调用在失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。

降级方法:

两种服务降级的方式分别可以通过dubbo-admin的消费者管理界面中的“屏蔽”、“容错”来实现

consumer服务降级.jpg

dubbo 服务降级的实现方式(含伪代码)

集群容错

  • failover(默认),失败时自动重试其它服务器,重试次数通过retries配置
  • failfast,请求失败时立即报错,只发起一次调用
  • failsafe,请求失败时直接忽略
  • failback,请求失败时定时重发
  • forking,并行调用多个服务器,有一个成功即返回,浪费资源
  • broadcast,广播调用所有提供者,任意一台报错则报错,通常用于通知所有提供者更新缓存或日志等本地资源信息
<dubbo:service cluster="failsafe" />
<dubbo:reference cluster="failsafe" />

也可以通过springcloud hystrix来进行容错

dubbo-admin、dubbo-monitor

dubbo-admin

注: develop分支还在重构,建议使用稳定分支master分支

二、Getting Started

需求:

用户服务、订单服务,订单服务作为consumer,用户服务作为provider,订单服务调用用户服务

项目结构如下:

dubbo-demo

—-contract 定义接口契约以及公共的对象模型
—-order-user 用户服务
—-order-service 订单服务

2.1 pom引用(dubbo+spring)

dubbo 2.6版本之前的引用

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.5.3</version>
</dependency>

<dependency>
    <groupId>com.101tec</groupId>
    <artifactId>zkclient</artifactId>
    <version>0.8</version>
</dependency>

dubbo 2.6之后的引用

<!--dubbo依赖-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.6.2</version>
</dependency>
<!--操作zookeeper客户端,2.6之前使用zkClient,之后使用curator-->
<!--注意:curator的版本必须与zookeeper服务器版本匹配,比如示例zk版本是3.4.13,必须使用2.x.x版本的curator才可以-->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>2.13.0</version>
</dependency>

本示例使用dubbo2.6.2,user-service以及order-service都添加新版pom引用

2.2 proivder用户服务

provider配置(user-service.xml)

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

    <!--dubbo xml schema配置官方文档:http://dubbo.apache.org/zh-cn/docs/user/references/xml/introduction.html-->

    <!--1. 指定服务提供者名称,用于注册到注册中心-->
    <dubbo:application name="user-service"></dubbo:application>
    <!--2. 指定zookeeper注册中心地址-->
    <dubbo:registry address="zookeeper://192.168.255.132:2181"></dubbo:registry>
    <!--3. 指定通信协议、端口等-->
    <dubbo:protocol name="dubbo" port="20880"></dubbo:protocol>
    <!--4. 暴露提供者服务,指定服务的实现对象-->
    <dubbo:service interface="com.qigang.dd.contract.api.UserService" ref="userService"></dubbo:service>
    <bean id="userService" class="com.qigang.dd.user.service.provider.UserServiceImpl"></bean>

    <!--5. 配置监控中心地址(可选,如果需要监控则配置)-->
    <dubbo:monitor protocol="registry"></dubbo:monitor>
</beans>

接口实现UserServiceImpl.java

//consumer
public class UserServiceImpl implements UserService {
	@Override
	public List<UserAddress> getUserAddressList(String userId) {
		//...
	}
}

服务入口启动函数

import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
public class UserServiceApp {
    public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"user-service.xml"});
        context.start();
        //按任意键退出
        System.in.read();
    }
}

2.3 consumer订单服务

consumer配置(order-service.xml)

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

    <!--【dubbo xml schema配置官方文档】http://dubbo.apache.org/zh-cn/docs/user/references/xml/introduction.html-->

    <!--扫描OrderServiceImpl-->
    <context:component-scan base-package="com.qigang.dd.order.service.provider"></context:component-scan>

    <!--1. 指定服务提供者名称,用于注册到注册中心-->
    <dubbo:application name="order-service"></dubbo:application>
    <!--2. 指定zookeeper注册中心地址-->
    <dubbo:registry address="zookeeper://192.168.255.132:2181"></dubbo:registry>
    <!--3. 引用远程服务-->
    <dubbo:reference interface="com.qigang.dd.contract.api.UserService" id="userService"></dubbo:reference>

    <!--4. 配置监控中心地址(可选,如果需要监控则配置)-->
    <dubbo:monitor protocol="registry"></dubbo:monitor>
</beans>

OrderServiceImpl中注入远程服务UserService

import com.qigang.dd.contract.api.OrderService;
import com.qigang.dd.contract.api.UserService;
import com.qigang.dd.contract.bean.UserAddress;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class OrderServiceImpl implements OrderService {
	@Autowired
	UserService userService;

	@Override
	public List<UserAddress> initOrder(String userId) {
		System.out.println("用户id:"+userId);
		List<UserAddress> addressList = userService.getUserAddressList(userId);
		//打印从用户服务获取到的地址列表
		addressList.forEach(ua-> System.out.println(ua.getUserAddress()));
		return addressList;
	}
}

入口启动函数,调用订单服务中的方法,实现远程调用用户服务

import com.qigang.dd.contract.api.OrderService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
public class OrderServiceApp {
    public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"order-service.xml"});
        context.start();

        OrderService orderService = context.getBean(OrderService.class);
        orderService.initOrder("1");
        System.in.read();
    }
}

2.4 contract契约接口模型层

将用户服务、订单服务公用的接口及模型提取到独立的module(contract)中,减少重复代码

//用户地址模型,必须实现Serializable接口
import java.io.Serializable;
public class UserAddress implements Serializable {
	private Integer id;
    private String userAddress; //用户地址
    private String userId; //用户id
    private String consignee; //收货人
    private String phoneNum; //电话号码
    private String isDefault; //是否为默认地址    Y-是     N-否
    
    //getters & setters...
}

//用户服务暴露的接口
import com.qigang.dd.contract.bean.UserAddress;
import java.util.List;
public interface UserService {
	List<UserAddress> getUserAddressList(String userId);
}

//订单服务暴露的接口
import com.qigang.dd.contract.bean.UserAddress;
import java.util.List;
public interface OrderService {
	List<UserAddress> initOrder(String userId);
}

2.5 启动zookeeper

2.6 启动dubbo-admin, dubbo-monitor

dubbo-admin项目checkout出来,切换master稳定分支,修改dubbo-admin module的resources/application.properties中的注册中心地址,修改dubbo-monitor-simple module 的resources/conf/dubbo.properties中的注册中心地址,两个注册中心地址相同

dubbo.registry.address=zookeeper://192.168.255.132:2181

根目录执行maven命令打包后通过java -jar执行target/xxx.jar来启动dubbo-admin和dubbo-monitor-simple

mvn clean package

或者直接idea中启动2个项目本地跑起来

2.7 启动provider, consumer

观察zookeeper、dubbo-admin、dubbo-monitor-simple中的数据

三、dubbo整合springboot

dubbo整合springboot需要依赖dubbo-spring-boot-starter,该组件存在两个版本:

dubbo-spring-boot-starter:这个是alibaba最初开源的项目,对应的maven仓库地址在这里,目前最新版本是2.0.0,不支持springboot 2.0,估计之后也不会再维护了,所以不建议使用,有一套示例代码供参考

dubbo-spring-boot-project:这个是贡献给apache之后的开源地址,新的版本从v2.7.0~v2.7.1,对应的maven仓库地址在这里

项目结构如下:

dubbo-demo

—-contract 定义接口契约以及公共的对象模型
—-order-user-spring-boot 用户服务
—-order-service-spring-boot 订单服务

根据apache版本的github上的说明,列出dubbo及springboot的配套版本列表如下:

dubbo-spring-boot-starter Dubbo Spring Boot 说明
2.7.1 2.7.1 2.x 有BUG,不建议生产使用
2.7.0 2.7.0 2.x 有BUG,不建议生产使用
0.2.1.RELEASE 2.6.5+ 2.x 是支持 Spring Boot 2.x 的主要版本(推荐,长期维护)
0.1.2.RELEASE 2.6.5+ 1.x 是支持 Spring Boot 1.x 的维护版本(兼容,短期维护)

3.1 dubbo-spring-boot-starter v2.7.x

截止到今天(2019-06-02),dubbo v2.7.1是已发布的最新版本,注册中心有重大问题所以不作演示,v2.7.0也有用户反馈有注册中心问题,但不影响作示例使用,生产应该还是2.7之前的老版本比较稳定,原来的老版本都是0.1.x~0.2.x,现在一下子跳到2.7.x,看样子之后的版本dubbo-spring-boot-starter的新版本号估计会跟dubbo的版本号保持一致

3.1.1 pom引用

provider、consumer的pom依赖一致即可

最新官方github说明现在应该没有及时维护,按上面的步骤无法编译应用,经过折腾,添加完整的pom依赖在下方

<properties>
    <spring-boot.version>2.1.1.RELEASE</spring-boot.version>
    <dubbo.version>2.7.0</dubbo.version>
</properties>

<dependencyManagement>
    <dependencies>
        <!-- Spring Boot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <!-- Apache Dubbo  -->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-dependencies-bom</artifactId>
            <version>${dubbo.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
            <version>${dubbo.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>javax.servlet</groupId>
                    <artifactId>servlet-api</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>log4j</groupId>
                    <artifactId>log4j</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>${spring-boot.version}</version>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>${dubbo.version}</version>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo</artifactId>
    </dependency>

    <!--zk依赖,注意需要与服务端安装的zk版本一致,本次示例zk版本为3.4.13-->
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-recipes</artifactId>
        <version>2.13.0</version>
        <exclusions>
            <exclusion>
                <groupId>org.apache.zookeeper</groupId>
                <artifactId>zookeeper</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.4.13</version>
    </dependency>

    <!--公用契约接口、契约模型依赖-->
    <dependency>
        <groupId>com.qigang</groupId>
        <artifactId>contract</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

3.1.2 provider用户服务

import com.qigang.dd.contract.api.UserService;
import com.qigang.dd.contract.bean.UserAddress;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;

//注意:这里的@Service是apache dubbo命名空间下的
@Service(interfaceClass = UserService.class)
@Component
public class UserServiceImpl implements UserService {
	@Override
	public List<UserAddress> getUserAddressList(String userId) {
		//...
	}
}

用户服务的启动类是一个普通的springboot启动类,不需要任何其他的annotation,比如老版本的@EnableDubbo @EnableDubboConfiguration都不需要

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class UserServiceSpringBootApp {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceSpringBootApp.class,args);
    }
}

springboot的配置也跟之前的版本有区别,dubbo的配置不需要spring开头了

spring.application.name=user-service-spring-boot
dubbo.scan.base-packages=com.qigang.user.service.sb.service
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
dubbo.registry.address=zookeeper://192.168.255.132:2181
dubbo.monitor.protocol=registry

server.port=9091

3.1.3 consumer订单服务

通过@Reference注入远程服务UserService,注意如果添加版本号,则只能调用对应版本的服务,本示例不添加版本号参数version

import com.qigang.dd.contract.api.UserService;
import com.qigang.dd.contract.bean.UserAddress;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
@RequestMapping("/order")
public class OrderController {
    @Reference(interfaceClass = UserService.class)
    UserService userService;

    @GetMapping("/initOrder")
    public List<UserAddress> initOrder(){
        List<UserAddress> addressList = userService.getUserAddressList("1");
        //打印从用户服务获取到的地址列表
        addressList.forEach(ua-> System.out.println(ua.getUserAddress()));
        return addressList;
    }
}

consumer springboot应用启动入口类同样是一个普通的springboot启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class OrderServiceSpringBootApp {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceSpringBootApp.class);
    }
}

springboot dubbo配置也同样不需要spring开头

spring.application.name=order-service-spring-boot
dubbo.registry.address=zookeeper://192.168.255.132:2181
dubbo.monitor.protocol=registry

server.port=9092

3.2 dubbo-spring-boot-starter v0.2.x(2019-06-08目前建议使用的最新稳定版本)

apache版本的 dubbo-spring-boot-starter v0.1.x 以及 dubbo-spring-boot-starter v0.2.x 都在不同的分支上维护,每个分支都有对应的readme可以参考

注意:v2.7.x 的pom依赖和v0.1.x/v0.2.x的pom依赖,groupId是不一样的

本次拿最新0.2.1.RELEASE版本做示例(目前最新稳定版本,线上建议使用该版本配置)

项目结构如下:

dubbo-demo

—-contract 定义接口契约以及公共的对象模型
—-order-user-spring-boot-021 用户服务
—-order-service-spring-boot-021 订单服务

3.2.1 pom引用

<properties>
    <spring-boot-version>2.1.1.RELEASE</spring-boot-version>
    <dubbo.version>2.6.5</dubbo.version>
    <dubbo-spring-boot-starter-version>0.2.1.RELEASE</dubbo-spring-boot-starter-version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot-version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo-dependencies-bom</artifactId>
            <version>${dubbo.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <!--springboot依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>${spring-boot-version}</version>
    </dependency>

    <!--dubbo-spring-boot-starter依赖-->
    <dependency>
        <groupId>com.alibaba.boot</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>${dubbo-spring-boot-starter-version}</version>
    </dependency>

    <!--dubbo依赖-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>dubbo</artifactId>
        <version>${dubbo.version}</version>
    </dependency>

    <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
    </dependency>

    <!--zk依赖,注意需要与服务端安装的zk版本一致,本次示例zk版本为3.4.13-->
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-recipes</artifactId>
        <version>2.13.0</version>
        <exclusions>
            <exclusion>
                <groupId>org.apache.zookeeper</groupId>
                <artifactId>zookeeper</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.4.13</version>
    </dependency>

    <!--公用契约接口、契约模型依赖-->
    <dependency>
        <groupId>com.qigang</groupId>
        <artifactId>contract</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

3.2.2 provider用户服务

import com.alibaba.dubbo.config.annotation.Service;
import com.qigang.dd.contract.api.UserService;
import com.qigang.dd.contract.bean.UserAddress;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;

//注意:这里的@Service是apache dubbo命名空间下的
@Service(interfaceClass = UserService.class)
@Component
public class UserServiceImpl implements UserService {
	@Override
	public List<UserAddress> getUserAddressList(String userId) {
		//...
	}
}

启动类需要加上@EnableDubbo,如果不加的话application.properties必须添加dubbo.scan.base-packages配置来扫描包

import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableDubbo
@SpringBootApplication
public class UserServiceSpringBootApp {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceSpringBootApp.class,args);
    }
}

配置文件application.properties

dubbo.application.name=user-service-spring-boot
dubbo.scan.base-packages=com.qigang.user.service.sb021.service
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
dubbo.registry.address=zookeeper://192.168.255.132:2181
dubbo.monitor.protocol=registry

#这个配置是用来解决bug的, https://github.com/apache/dubbo/issues/3193
spring.main.allow-bean-definition-overriding=true

server.port=9091

3.2.3 consumer订单服务

注入远程用户服务

import com.alibaba.dubbo.config.annotation.Reference;
import com.qigang.dd.contract.api.UserService;
import com.qigang.dd.contract.bean.UserAddress;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
@RequestMapping("/order")
public class OrderController {
    @Reference(interfaceClass = UserService.class)
    UserService userService;

    @GetMapping("/initOrder")
    public List<UserAddress> initOrder(){
        //...
    }
}

启动类就是普通的springboot启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class OrderServiceSpringBootApp {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceSpringBootApp.class);
    }
}

配置文件application.properties

dubbo.application.name=order-service-spring-boot
dubbo.registry.address=zookeeper://192.168.255.132:2181
dubbo.monitor.protocol=registry

server.port=9092

3.3 【不推荐】通过dubbo xml配置文件方式整合springboot

上面3.1、3.2中的starter示例都是通过application.properties文件的方式来将dubbo集成到springboot中,这种方式可以使用,但是有个问题,如果你想在实际项目中针对方法级别做一些特定配置,比如provider中UserServiceImpl中的getUserAddressList这个方法指定它的默认timeout=5000,而UserServiceImpl中的其它方法还是保持默认的timeout=1000,那仅仅使用application.properties就无法配置,通过原生的dubbo xml的配置方式可以实现,但是不推荐使用这种方式,建议尽量少用xml配置文件,公司内部一般情况下都有配置中心,建议使用annotation方式对接配置中心。

本次还是拿最新0.2.1.RELEASE版本做示例(目前最新稳定版本,线上建议使用该版本配置)

项目结构如下:

dubbo-demo springboot-xml-config 分支

—-contract 定义接口契约以及公共的对象模型
—-order-user-spring-boot-021 用户服务
—-order-service-spring-boot-021 订单服务

3.3.1 pom依赖

pom依赖同3.2.1

3.3.2 provider用户服务

import com.qigang.dd.contract.api.UserService;
import com.qigang.dd.contract.bean.UserAddress;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;

//这里不需要alibaba的@Service,直接配置在xml文件里面
@Component
public class UserServiceImpl implements UserService {
	@Override
	public List<UserAddress> getUserAddressList(String userId) {
		System.out.println("UserServiceImpl..3.....");
		UserAddress address1 = new UserAddress(1, "北京市昌平区宏福科技园综合楼3层", "1", "李老师", "010-56253825", "Y");
		UserAddress address2 = new UserAddress(2, "深圳市宝安区西部硅谷大厦B座3层(深圳分校)", "1", "王老师", "010-56253825", "N");

		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		/*if(Math.random()>0.5) {
			throw new RuntimeException();
		}*/
		return Arrays.asList(address1,address2);
	}
}

springboot入口类通过@ImportResource来引入dubbo xml配置文件

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;

@ImportResource(locations = "classpath:user-service.xml")
@SpringBootApplication
public class UserServiceSpringBootApp {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceSpringBootApp.class,args);
    }
}

具体user-service.xml内容

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

    <!--dubbo xml schema配置官方文档:http://dubbo.apache.org/zh-cn/docs/user/references/xml/introduction.html-->

    <!--1. 指定服务提供者名称,用于注册到注册中心,本次不需要该配置,配上会报错,application.name配置在application.properties文件中了-->
    <!--<dubbo:application name="user-service-springboot-xml-config"></dubbo:application>-->

    <!--2. 指定zookeeper注册中心地址-->
    <dubbo:registry address="zookeeper://192.168.255.132:2181"></dubbo:registry>
    <!--3. 指定通信协议、端口等-->
    <dubbo:protocol name="dubbo" port="20880"></dubbo:protocol>
    <!--4. 暴露提供者服务,指定服务的实现对象-->
    <dubbo:service interface="com.qigang.dd.contract.api.UserService" ref="userService">
        <!--<dubbo:method name="getUserAddressList" timeout="2000"></dubbo:method>-->
    </dubbo:service>
    <bean id="userService" class="com.qigang.user.service.sb021.service.UserServiceImpl"></bean>

    <!--5. 配置监控中心地址(可选,如果需要监控则配置)-->
    <!--<dubbo:monitor protocol="registry"></dubbo:monitor>-->
</beans>

基础的application.properties文件内容

dubbo.application.name=user-service-springboot-xml-config
spring.main.allow-bean-definition-overriding=true
server.port=9091

3.3.3 consumer订单服务

import com.alibaba.dubbo.config.annotation.Reference;
import com.qigang.dd.contract.api.UserService;
import com.qigang.dd.contract.bean.UserAddress;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
@RequestMapping("/order")
public class OrderController {
    //@Reference(interfaceClass = UserService.class, timeout = 2500)
    //如果xml配置文件中配置了dubbo:reference,则不需要使用alibaba的@Reference这个annotation,直接使用@Autowired即可
    @Autowired
    UserService userService;

    @GetMapping("/initOrder")
    public List<UserAddress> initOrder(){
        List<UserAddress> addressList = userService.getUserAddressList("1");
        //打印从用户服务获取到的地址列表
        addressList.forEach(ua-> System.out.println(ua.getUserAddress()));
        return addressList;
    }
}

同样的springboot入口函数需要引入dubbo xml配置文件

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;

@ImportResource(locations = "classpath:order-service.xml")
@SpringBootApplication
public class OrderServiceSpringBootApp {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceSpringBootApp.class);
    }
}

具体的order-service.xml的内容

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

    <!--【dubbo xml schema配置官方文档】http://dubbo.apache.org/zh-cn/docs/user/references/xml/introduction.html-->

    <!--1. 指定服务提供者名称,用于注册到注册中心,本次不需要该配置,配上会报错,application.name配置在application.properties文件中了-->
    <!--<dubbo:application name="order-service-springboot-xml-config"></dubbo:application>-->
    <!--2. 指定zookeeper注册中心地址-->
    <dubbo:registry address="zookeeper://192.168.255.132:2181"></dubbo:registry>
    <!--3. 引用远程服务-->
    <dubbo:reference interface="com.qigang.dd.contract.api.UserService" id="userService">
        <dubbo:method name="getUserAddressList" timeout="3000"></dubbo:method>
    </dubbo:reference>

    <!--4. 配置监控中心地址(可选,如果需要监控则配置)-->
    <!--<dubbo:monitor protocol="registry"></dubbo:monitor>-->
</beans>

基础的springboot配置文件application.properties内容

dubbo.application.name=order-service-springboot-xml-config
server.port=9092

3.4 【推荐】通过annotation代码配置方式整合springboot

还是拿最新0.2.1.RELEASE版本做示例(目前最新稳定版本,线上建议使用该版本配置)

官方文档

项目结构如下:

dubbo-demo springboot-annotation-config 分支

—-contract 定义接口契约以及公共的对象模型
—-order-user-spring-boot-021 用户服务
—-order-service-spring-boot-021 订单服务

3.4.1 pom引用

pom依赖同3.2.1

3.4.2 provider用户服务

配置类

import com.alibaba.dubbo.config.*;
import com.qigang.dd.contract.api.UserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;

@Configuration
public class DubboProviderConfiguration {
    //dubbo2.6.5+starter0.2.1版本不能在配置xml或者配置代码中主动配置application节点,否则会报节点冲突,应该是个BUG
    //只能在application.properties里面配置dubbo.application.name
    /*@Bean
    public ApplicationConfig applicationConfig(){
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("user-service-spring-boot-annotation-config");
        return applicationConfig;
    }*/

    @Bean
    public RegistryConfig registryConfig(){
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("zookeeper://192.168.255.132:2181");
        return registryConfig;
    }

    @Bean
    public ProtocolConfig protocolConfig(){
        ProtocolConfig protocolConfig = new ProtocolConfig();
        protocolConfig.setName("dubbo");
        protocolConfig.setPort(20880);
        return protocolConfig;
    }

    @Bean
    public MonitorConfig monitorConfig(){
        MonitorConfig monitorConfig = new MonitorConfig();
        monitorConfig.setProtocol("registry");
        return monitorConfig;
    }

    @Bean
    public ServiceConfig<UserService> serviceConfig(UserService service){
        ServiceConfig<UserService> serviceConfig = new ServiceConfig<>();
        serviceConfig.setInterface(UserService.class);
        serviceConfig.setRef(service);

        //设置方法级别的配置
        MethodConfig methodConfig = new MethodConfig();
        methodConfig.setName("getUserAddressList");
        methodConfig.setTimeout(2000);
        serviceConfig.setMethods(Arrays.asList(methodConfig));

        return serviceConfig;
    }
}

springboot入口类

import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

//使用@EnableDubbo来扫描dubbo配置类,或者使用@DubboComponentScan
//@EnableDubbo
@DubboComponentScan("com.qigang.user.service.sb021")
@SpringBootApplication
public class UserServiceSpringBootApp {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceSpringBootApp.class,args);
    }
}

3.4.2 consumer订单服务

配置类

import com.alibaba.dubbo.config.*;
import com.qigang.dd.contract.api.UserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;

@Configuration
public class DubboConsumerConfiguration {
    //dubbo2.6.5+starter0.2.1版本不能在配置xml或者配置代码中主动配置application节点,否则会报节点冲突,应该是个BUG
    //只能在application.properties里面配置dubbo.application.name
    /*@Bean
    public ApplicationConfig applicationConfig(){
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("order-service-spring-boot-annotation-config");
        return applicationConfig;
    }*/

    @Bean
    public RegistryConfig registryConfig(){
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("zookeeper://192.168.255.132:2181");
        return registryConfig;
    }

    @Bean
    public MonitorConfig monitorConfig(){
        MonitorConfig monitorConfig = new MonitorConfig();
        monitorConfig.setProtocol("registry");
        return monitorConfig;
    }

    //consumer端的ReferenceConfig不知道为什么不生效,有可能是BUG
    //可以通过@Reference来进行服务级别的设置
    /*@Bean
    public ReferenceConfig referenceConfig(){
        ReferenceConfig<UserService> referenceConfig = new ReferenceConfig<>();
        referenceConfig.setInterface(UserService.class);
        referenceConfig.setId("userService");

        //设置方法级别的配置
        MethodConfig methodConfig = new MethodConfig();
        methodConfig.setName("getUserAddressList");
        methodConfig.setTimeout(2000);
        referenceConfig.setMethods(Arrays.asList(methodConfig));

        return referenceConfig;
    }*/
}

springboot入口类

import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

//使用@EnableDubbo来扫描dubbo配置类,或者使用@DubboComponentScan
//@EnableDubbo
@DubboComponentScan("com.qigang.user.service.sb021")
@SpringBootApplication
public class UserServiceSpringBootApp {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceSpringBootApp.class,args);
    }
}

参考

dubbo官方文档

dubbo生态

深入浅出微服务框架dubbo(一):基础篇

github apache dubbo official repo

github apache dubbo samples

dubbo-spring-boot-starter

dubbo:9个你不一定知道,但好用的功能

***Dubbo基础及原理机制