Dubbo 配置

一、覆盖策略

JVM 启动 -D 参数优先,这样可以使用户在部署和启动时进行参数重写,比如在启动时需改变协议的端口。

XML 次之,如果在 XML 中有配置,则 dubbo.properties 中的相应配置项无效。

Properties 最后,相当于缺省值,只有 XML 没有配置时,dubbo.properties 的相应配置项才会生效,通常用于共享公共配置,比如应用名。

优先权:dubbo.properties < dubbo.xml < -D 参数

我们复制一节的项目,来演示。

1. 我们在resources 目录下创建 dubbo.propertites ,内容如下

dubbo.protocol.port=20882

2. application.properties 内容

#就是服务名,不能跟别的dubbo提供端重复
dubbo.application.name=gmall-user-provider

#是指定注册中心协议
dubbo.registry.protocol=zookeeper

#注册中心的地址加端口号
dubbo.registry.address=127.0.0.1:2181

#注解方式要扫描的包

dubbo.scan.base-package=com.gf

#是分布式固定是dubbo,不要改
dubbo.protocol.name=dubbo

#服务暴露端口
dubbo.protocol.port=20881

#表示从注册中心发现监控中心地址
dubbo.monitor.protocol=registry

3. 设置VM参数

我们运行项目测试结果如下:

这说明VM参数配置的优先权最高。

我们去掉VM参数测试如下:

我们最后再去掉application.properties中的 服务暴露端口配置,测试如下:

所以我得出dubbo的配置优先权:dubbo.properties < dubbo.xml < -D 参数

二、启动时检查

当我们先启动 服务消费者,没有先启动 服务提供者进服务注册到注册中心时,是会报错的。报错信息 为没有可用的服务提供者

我们可以通过设置来关闭 服务消费者 ,对远程服务的检查:

方式1
注解 @Reference 中有个属性 check 我为设置为 false ,就可以关闭启动是时对该服务的检查,到真正使用时才检查是否可用:

@Service
public class OrderServiceImpl implements OrderService {

    @Reference(check = false)
    UserService userService;


    @Override
    public List<UserAddress> initOrder(String userId) {
        System.out.println( "用户id : " + userId );
        //查询用户地址
        List<UserAddress> addressList = userService.getUserAddressList( userId );
        return addressList;
    }
}

我重启动消费者 ,发现已经正常了。

我们的演示项目中远程服务少 ,如果服务远程服务比较多,又想去掉启东时检测,我们一个个的设置 ,比较麻烦 ,Dubbo为我提供了统一配置:

dubbo.consumer.check=false

三、配置覆盖关系

1. timeout

以 timeout 为例,显示了配置的查找顺序,其它 retries, loadbalance, actives 等类似:

  • 方法级优先,接口级次之,全局配置再次之。
  • 如果级别一样,则消费方优先,提供方次之。
    其中,服务提供方配置,通过 URL 经由注册中心传递给消费方。

Dubbo官方建议由服务提供方设置超时,因为一个方法需要执行多长时间,服务提供方更清楚,如果一个消费方同时引用多个服务,就不需要关心每个服务的超时设置。

服务端 通过 Dubbo 的@Service 注解设置实例:

@Service(timeout = 3000)
@Component
public class UserServiceImpl implements UserService{


    @Override
    public List<UserAddress> getUserAddressList(String userId) {

        List<UserAddress> list = new ArrayList<>();
        UserAddress address1 = new UserAddress(1 , "上海市杨浦区xxx路xxx号" , "1" , "王某某","0");
        UserAddress address2 = new UserAddress(2 , "上海市徐汇区xxx路xxx号" , "1" , "张某某","1");

        list.add( address1 );
        list.add( address2 );

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

        return list;
    }
}

我们远程访问接口测试结果如下,出现了等待服务器端响应超时的错误。

2. retries

timeout 一般配合 retries(重试次数,不包含第一次调用)使用

@Service(timeout = 3000 , retries = 3)
@Component
public class UserServiceImpl implements UserService{


    @Override
    public List<UserAddress> getUserAddressList(String userId) {
        System.out.println("UserServiceImpl 被调用...");
        List<UserAddress> list = new ArrayList<>();
        UserAddress address1 = new UserAddress(1 , "上海市杨浦区xxx路xxx号" , "1" , "王某某","0");
        UserAddress address2 = new UserAddress(2 , "上海市徐汇区xxx路xxx号" , "1" , "张某某","1");

        list.add( address1 );
        list.add( address2 );

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

        return list;
    }
}

访问远程接口 测试结果如下,“UserServiceImpl 被调用…” 会打印 4 次

通常正式环境,我们的服务提供者会部署多个 ,那么一般是调用失败后,会轮询重试各个服务,本例如果我们部署3台机器,访问的是server1 ,那么server1 会先打印1次 ,然后重试 server1、server2、server3 会各打印1次。

retries 应该在合适的时候使用,一般如果方法的访问是幂等 的,我们可以使用(一般情况下我们应该把 查询、删除、修改的方法 设计成幂等的)。

四、多版本

当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。

可以按照以下的步骤进行版本迁移:

    1. 在低压力时间段,先升级一半提供者为新版本
    1. 再将所有消费者升级为新版本
    1. 然后将剩下的一半提供者升级为新版本

实例

我们在服务提供方再创建一个UserService的实现类 UserServiceImpl2

1. UserServiceImpl
@Service(version = "1.0.0")
@Component
public class UserServiceImpl implements UserService{


    @Override
    public List<UserAddress> getUserAddressList(String userId) {
        System.out.println("UserServiceImpl 旧版本...");
        List<UserAddress> list = new ArrayList<>();
        UserAddress address1 = new UserAddress(1 , "上海市杨浦区xxx路xxx号" , "1" , "王某某","0");
        UserAddress address2 = new UserAddress(2 , "上海市徐汇区xxx路xxx号" , "1" , "张某某","1");

        list.add( address1 );
        list.add( address2 );

        return list;
    }
}
2. UserServiceImpl
@Service(version = "2.0.0")
@Component
public class UserServiceImpl2 implements UserService {


    @Override
    public List<UserAddress> getUserAddressList(String userId) {
        System.out.println( "UserServiceImpl 新版本..." );
        List<UserAddress> list = new ArrayList<>();
        UserAddress address1 = new UserAddress( 1, "上海市杨浦区xxx路xxx号", "1", "王某某", "0" );
        UserAddress address2 = new UserAddress( 2, "上海市徐汇区xxx路xxx号", "1", "张某某", "1" );

        list.add( address1 );
        list.add( address2 );

        return list;
    }
}
3. OrderServiceImpl

我们之后就可以在服务消费方的 @Reference 设置调用的服务版本。

@Service
public class OrderServiceImpl implements OrderService {

    @Reference(version = "2.0.0")
    UserService userService;


    @Override
    public List<UserAddress> initOrder(String userId) {
        System.out.println( "用户id : " + userId );
        //查询用户地址
        List<UserAddress> addressList = userService.getUserAddressList( userId );
        return addressList;
    }
}

启动服务提供者和消费者 ,访问远程接口测试结果如下,打印的是 “新版本” 说明我们调用的就是 “2.0.0” 版本的服务。这也就实现Dubbo官方说的 灰度发布

五、本地存根

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

1. 创建UserServiceSub

我们在服务消费方创建 UserServiceSub 并实现 UserService 接口

public class UserServiceStub implements UserService{

    private final UserService userService;

    // 构造函数传入真正的远程代理对象
    public UserServiceStub(UserService userService) {
        this.userService = userService;
    }

    @Override
    public List<UserAddress> getUserAddressList(String userId) {
        System.out.println("UserServiceStub ...");
        // 此代码在客户端执行, 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等
        if (!StringUtils.isEmpty( userId )) {
            return userService.getUserAddressList( userId );
        }

        // 你可以容错,可以做任何AOP拦截事项
        return null;

    }
}
2. OrderServiceImpl

通过Dubbo 的**@Reference** 的 stub 属性 使用本地存根

@Service
public class OrderServiceImpl implements OrderService {

    @Reference(stub = "com.gf.service.impl.UserServiceStub")
    UserService userService;


    @Override
    public List<UserAddress> initOrder(String userId) {
        System.out.println( "用户id : " + userId );
        //查询用户地址
        List<UserAddress> addressList = userService.getUserAddressList( userId );
        return addressList;
    }
}

我们访问远程接口时,服务消费者会先走存根 ,验证参数userId是否为空:

扫码关注我的公众号,精彩内容不能错过!
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值