dubbo系列二:dubbo常用功能总结(1)

1. 注解配置

dubbo可以使用注解在生产者端暴露服务接口和在消费端引用接口,只需要在生产者和消费者的配置文件里面配置扫描包路径即可,而不用在xml里面配置需要暴露和引用的接口

扫描包路径的配置

<!-- 扫描注解包路径,多个包用逗号分隔,不填pacakge表示扫描当前ApplicationContext中所有的类 -->
    <dubbo:annotation package="com.study.service" />

1.1 在生产者dubbo-provider-web和消费者dubbo-consumer-web新建一个dubbo注解测试的接口

dubbo系列二:dubbo常用功能总结(1)

package com.study.service;

/**
 * 
* @Description: dubbo注解测试的接口
* @author leeSmall
* @date 2018年10月23日
*
 */
public interface AnnotationDubboTest {
    public String eat(String param);
}

dubbo系列二:dubbo常用功能总结(1)

1.2 在生产者dubbo-provider-web新建一个dubbo注解测试的接口的实现类

dubbo系列二:dubbo常用功能总结(1)

package com.study.service;

import com.alibaba.dubbo.config.annotation.Service;

/**
 * 
* @Description: dubbo注解测试的接口的实现类
* @author leeSmall
* @date 2018年10月23日
*
 */
@Service(timeout = 1000000, version = "1.2.3")
public class AnnotationDubboTestImpl implements AnnotationDubboTest {
    
    public String eat(String param) {
        System.out.println("-----------AnnotationDubboTestImpl service test------------"
                + param);
        return "-----------AnnotationDubboTestImpl service test------------";
    }
    
}

dubbo系列二:dubbo常用功能总结(1)

1.3 在消费端dubbo-consumer-web新建一个测试的control

dubbo系列二:dubbo常用功能总结(1)

/**
 * 
 * @Description: dubbo消费端测试control
 * @author leeSmall
 * @date 2018年10月23日
 *
 */
@Controller
@RequestMapping("/common")
public class CommonController implements ApplicationContextAware {
    
    private static Logger logger = Logger.getLogger(CommonController.class);
    
    @Reference(check = false, timeout = 100000, version = "1.2.3")
    AnnotationDubboTest annotationdubbo;
    
    @RequestMapping("/annotationdubbo")
    public @ResponseBody String annotationdubbo() {
        annotationdubbo.eat("我是dubbo的注解测试control");
        return "annotationdubbo";
    }

}

dubbo系列二:dubbo常用功能总结(1)

1.4 在tomcat8080和tomcat8081分别启动生产者和消费者,在浏览器输入地址http://localhost:8081/dubbo-consumer-web/common/annotationdubbo访问查看效果

生产者端:

dubbo系列二:dubbo常用功能总结(1)

浏览器:

dubbo系列二:dubbo常用功能总结(1)

2. 启动时检查

Dubbo缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止Spring初始化完成,以便上线时,能及早发现问题,默认 check="true" 。
可以通过 check="false" 关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。
另外,如果你的Spring容器是懒加载的,或者通过API编程延迟引用服务,请关闭 check,否则服务临时不可用时,会抛出异常,拿到null引用,如果 check="false" ,总是会返回引用,当服务恢复时,能自动连上。

关闭某个服务的启动时检查 (没有提供者时报错):

<dubbo:reference interface="com.foo.BarService" check="false" />

关闭所有服务的启动时检查 (没有提供者时报错):

<dubbo:consumer check="false" />

3. 集群容错

3.1 Failover Cluster

失败自动切换,缺省值,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="2" 来设置重试次数(不含第一次)。
配置如下:
生产者:
<dubbo:service retries="2" />
消费者:
<dubbo:reference retries="2" />
消费者具体到调用生产者的哪个方法:
<dubbo:reference>
<dubbo:method name="findFoo" retries="2" />
</dubbo:reference>

3.2 Failfast Cluster

快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录
配置如下:
生产者:
<dubbo:service cluster="failfast" />
消费者:
<dubbo:reference cluster="failfast" />

3.3 Failsafe Cluster

失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作
配置如下:
生产者:
<dubbo:service cluster="failsafe" />
消费者:
<dubbo:reference cluster="failsafe" />

3.4 Failback Cluster

失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作
配置如下:
生产者:
<dubbo:service cluster="failback" />
消费者:
<dubbo:reference cluster="failback" />

3.5 Forking Cluster

并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。
配置如下:
生产者:
<dubbo:service cluster=“forking" />
消费者:
<dubbo:reference cluster=“forking" />

3.6 Broadcast Cluster

广播调用所有提供者,逐个调用,任意一台报错则报错 。通常用于通知所有提供者更新缓存或日志等本地资源信息
配置如下:
生产者:
<dubbo:service cluster="broadcast" />
消费者:
<dubbo:reference cluster="broadcast" />

4. 负载均衡

4.1 Random LoadBalance

随机,按权重设置随机概率。
在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。

配置如下:

dubbo系列二:dubbo常用功能总结(1)

<dubbo:service interface="..." loadbalance="random" />
或:
<dubbo:reference interface="..." loadbalance="random" />
或:
<dubbo:service interface="...">
    <dubbo:method name="..." loadbalance="random"/>
</dubbo:service>
或:
<dubbo:reference interface="...">
    <dubbo:method name="..." loadbalance="random"/>
</dubbo:reference>

dubbo系列二:dubbo常用功能总结(1)

4.2 RoundRobin LoadBalance

轮循,按公约后的权重设置轮循比率。
存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。

配置如下:

dubbo系列二:dubbo常用功能总结(1)

<dubbo:service interface="..." loadbalance="roundrobin" />
或:
<dubbo:reference interface="..." loadbalance="roundrobin" />
或:
<dubbo:service interface="...">
    <dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:service>
或:
<dubbo:reference interface="...">
    <dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:reference>

dubbo系列二:dubbo常用功能总结(1)

4.3 ConsistentHash LoadBalance

一致性 Hash,相同参数的请求总是发到同一提供者。
当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
缺省只对第一个参数 Hash,如果要修改,请配置 
<dubbo:parameter key="hash.arguments"value="0,1" />
缺省用160份虚拟节点,如果要修改,
请配置 <dubbo:parameter key="hash.nodes" value="320" />
说明:
hash.arguments:当进行调用时候根据调用方法的哪几个参数生成key,并根据key来通过一致性hash算法来选择调用结点。例如调用方法invoke(String s1,String s2); 若hash.arguments为1(默认值),则仅取invoke的参数1(s1)来生成hashCode。
hash.nodes:为结点的副本数

dubbo系列二:dubbo常用功能总结(1)

<dubbo:service interface="..." loadbalance="consistenthash" />
或:
<dubbo:reference interface="..." loadbalance="consistenthash" />
或:
<dubbo:service interface="...">
    <dubbo:method name="..." loadbalance="consistenthash"/>
</dubbo:service>
或:
<dubbo:reference interface="...">
    <dubbo:method name="..." loadbalance="consistenthash"/>
</dubbo:reference>

dubbo系列二:dubbo常用功能总结(1)

4.4 LeastActive LoadBalance

最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。

dubbo系列二:dubbo常用功能总结(1)

<dubbo:service interface="..." loadbalance="leastactive" />
或:
<dubbo:reference interface="..." loadbalance="leastactive" />
或:
<dubbo:service interface="...">
    <dubbo:method name="..." loadbalance="leastactive"/>
</dubbo:service>
或:
<dubbo:reference interface="...">
    <dubbo:method name="..." loadbalance="leastactive"/>
</dubbo:reference>

dubbo系列二:dubbo常用功能总结(1)

5. 服务分组

当一个接口有多个实现时,可以用group区分要调用的服务。

5.1 服务分组配置方式实现:

在生产者dubbo-provider-web和消费者dubbo-consumer-web分别新建一个接口

package com.study.test.service;

public interface DubboTestService {
    public String eat(String param);
}

在生产者dubbo-provider-web新建两个DubboTestService接口的实现类

实现类1:

dubbo系列二:dubbo常用功能总结(1)

package com.study.test.service;

public class DubboTestServiceImpl implements DubboTestService {
    
    public String eat(String param) {
        
        System.out.println("-----------dubbo service test DubboTestServiceImpl ------------" + param);
        return "-----------dubbo service test DubboTestServiceImpl ------------";
    }
    
}

dubbo系列二:dubbo常用功能总结(1)

实现类2:

dubbo系列二:dubbo常用功能总结(1)

package com.study.test.service;

public class DubboTestService1Impl implements DubboTestService {
    
    public String eat(String param) {
        
        System.out.println("-----------dubbo service test DubboTestService1Impl------------" + param);
        return "-----------dubbo service test DubboTestService1Impl------------";
    }
    
}

dubbo系列二:dubbo常用功能总结(1)

在生产者dubbo-provider-web的applicationProvider.xml配置分组

    <!-- 服务分组 -->
    <bean id="dubboTestServiceImpl1" class="com.study.test.service.DubboTestServiceImpl"/>
    <bean id="dubboTestServiceImpl2" class="com.study.test.service.DubboTestService1Impl"/>
    <dubbo:service interface="com.study.test.service.DubboTestService" ref="dubboTestServiceImpl1" group="dubboTestServiceImpl1"/>
    <dubbo:service interface="com.study.test.service.DubboTestService" ref="dubboTestServiceImpl2" group="dubboTestServiceImpl2"/>

在消费者dubbo-consumer-web的applicationConsumer.xml配置调用的分组

    <!--服务分组  -->
    <dubbo:reference id="dubboTestServiceImpl1" interface="com.study.test.service.DubboTestService" check="false" retries="4" cluster="failover" group="dubboTestServiceImpl1"/>
    <dubbo:reference id="dubboTestServiceImpl2" interface="com.study.test.service.DubboTestService" check="false" retries="4" cluster="failover" group="dubboTestServiceImpl2"/>
    

在消费者dubbo-consumer-web的CommonController.java里面创建服务分组测试代码

dubbo系列二:dubbo常用功能总结(1)

//服务分组示例begin
    @Autowired
    @Qualifier("dubboTestServiceImpl1")
    DubboTestService dubboService1;
    
    @Autowired
    @Qualifier("dubboTestServiceImpl2")
    DubboTestService dubboService2;
    
    @RequestMapping("/dubboTest")
    public @ResponseBody String dubboTest() {
        dubboService1.eat("服务分组示例!");
        dubboService2.eat("服务分组示例!");
        return "dubboTest";
    }
    //服务分组示例end

dubbo系列二:dubbo常用功能总结(1)

在浏览器输入地址http://localhost:8081/dubbo-consumer-web/common/dubboTest访问查看效果

生产者:

dubbo系列二:dubbo常用功能总结(1)

浏览器:

dubbo系列二:dubbo常用功能总结(1)

5.2 服务分组注解方式实现:

 在生产者dubbo-provider-web和消费者dubbo-consumer-web分别新建一个接口

dubbo系列二:dubbo常用功能总结(1)

package com.study.service;

public interface UserService {
    
    public String login(String param);
    
}

dubbo系列二:dubbo常用功能总结(1)

在生产者dubbo-provider-web新建两个UserService接口的实现类

实现类1:

dubbo系列二:dubbo常用功能总结(1)

package com.study.service;

import org.apache.log4j.Logger;

import com.alibaba.dubbo.config.annotation.Service;

@Service(version = "1.0.2", group = "user2")
public class UserService2Impl implements UserService {
    
    private static Logger logger = Logger.getLogger(UserService2Impl.class);
    
    public String login(String param) {
        logger.info("UserService2Impl.login  begin!22222");
        return "用户已经登录成功!·~~~~~~~~~~~~~~~~~~";
    }
    
    
}

dubbo系列二:dubbo常用功能总结(1)

 实现类2:

dubbo系列二:dubbo常用功能总结(1)

package com.study.service;

import org.apache.log4j.Logger;

import com.alibaba.dubbo.config.annotation.Service;

@Service(version = "1.0.2", group = "user1")
public class UserServiceImpl implements UserService {
    
    private static Logger logger = Logger.getLogger(UserServiceImpl.class);
    
    public String login(String param) {
        logger.info("UserServiceImpl.login  begin!");
        return "用户已经登录成功!·~~~~~~~~~~~~~~~~~~";
    }
    
}

dubbo系列二:dubbo常用功能总结(1)

 在消费者dubbo-consumer-web的CommonController.java里面创建服务分组测试代码

dubbo系列二:dubbo常用功能总结(1)

//服务分组注解实现示例begin
    @Reference(version = "1.0.2", check = false, group = "user1")
    UserService usrService;
    
    @Reference(version = "1.0.2", check = false, group = "user2")
    UserService usr2Service;
    
    @RequestMapping("/grouplogin1")
    public @ResponseBody String login() {
        logger.info(usrService.login("服务分组注解实现"));
        logger.info(usr2Service.login("服务分组注解实现"));
        return "成功";
    }
    //服务分组注解实现示例end

dubbo系列二:dubbo常用功能总结(1)

在浏览器输入地址http://localhost:8081/dubbo-consumer-web/common/grouplogin1访问查看效果

生产者:

 dubbo系列二:dubbo常用功能总结(1)

消费者:

dubbo系列二:dubbo常用功能总结(1)

6. 多版本

当一个接口实现出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。
可以按照以下的步骤进行版本迁移:
1)在低压力时间段,先升级一半提供者为新版本
2)再将所有消费者升级为新版本
3)然后将剩下的一半提供者升级为新版本
老版本服务提供者配置:
<dubbo:service interface="com.foo.BarService" version="1.0.0" />

新版本服务提供者配置:
<dubbo:service interface="com.foo.BarService" version="2.0.0" />

老版本服务消费者配置:
<dubbo:reference id="barService" interface="com.foo.BarService" version="1.0.0" />

新版本服务消费者配置:
<dubbo:reference id="barService" interface="com.foo.BarService" version="2.0.0" />

如果不需要区分版本,可以按照以下的方式配置 :
<dubbo:reference id="barService" interface="com.foo.BarService" version="*" />

7. 参数验证

在生产者dubbo-provider-web和消费者dubbo-consumer-web的pom.xml里面分别引入如下依赖:

dubbo系列二:dubbo常用功能总结(1)

        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.0.0.GA</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>4.2.0.Final</version>
        </dependency>

dubbo系列二:dubbo常用功能总结(1)

在生产者dubbo-provider-web和消费者dubbo-consumer-web分别新建一个参数验证接口和一个参数验证实体

参数验证接口:

dubbo系列二:dubbo常用功能总结(1)

package com.study.service;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

/**
 * 
 * @Description: 参数验证接口
 *  缺省可按服务接口区分验证场景,如:@NotNull(groups = ValidationService.class)
 * @author leeSamll
 * @date 2018年10月23日
 *
 */
public interface ValidationService { 

    void save(ValidationParameter parameter);
    
    void update(ValidationParameter parameter);
    
    void delete(
            @Min(1) long id,
            @NotNull @Size(min = 2, max = 16) @Pattern(regexp = "^[a-zA-Z]+$") String operator);
    
    // 与方法同名接口,首字母大写,用于区分验证场景,如:@NotNull(groups = ValidationService.Save.class),可选
    @interface Save {
    } 
    
    // 与方法同名接口,首字母大写,用于区分验证场景,如:@NotNull(groups = ValidationService.Update.class),可选
    @interface Update {
    } 
    
}

dubbo系列二:dubbo常用功能总结(1)

参数验证实体:

dubbo系列二:dubbo常用功能总结(1)

package com.study.service;

import java.io.Serializable;
import java.util.Date;

import javax.validation.constraints.Future;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

/**
 * 
 * @Description: 参数验证实体
 * @author leeSamll
 * @date 2018年10月23日
 *
 */
public class ValidationParameter implements Serializable {
    
    private static final long serialVersionUID = 7158911668568000392L;
    
    // 不允许为空
    @NotNull
    // 长度或大小范围
    @Size(min = 2, max = 20)
    private String name;
    
    @NotNull(groups = ValidationService.Save.class)
    // 保存时不允许为空,更新时允许为空 ,表示不更新该字段
    @Pattern(regexp = "^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$")
    private String email;
    
    // 最小值
    @Min(18)
    // 最大值
    @Max(100)
    private int age;
    
    // 必须为一个过去的时间
    @Past
    private Date loginDate;
    
    // 必须为一个未来的时间
    @Future
    private Date expiryDate;
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public String getEmail() {
        return email;
    }
    
    public void setEmail(String email) {
        this.email = email;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    public Date getLoginDate() {
        return loginDate;
    }
    
    public void setLoginDate(Date loginDate) {
        this.loginDate = loginDate;
    }
    
    public Date getExpiryDate() {
        return expiryDate;
    }
    
    public void setExpiryDate(Date expiryDate) {
        this.expiryDate = expiryDate;
    }
    
}

dubbo系列二:dubbo常用功能总结(1)

在生产者dubbo-provider-web新建ValidationService接口的实现类

dubbo系列二:dubbo常用功能总结(1)

package com.study.service;

/**
 * 
 * @Description: 参数验证接口实现类
 * @author leeSamll
 * @date 2018年10月23日
 *
 */
public class ValidationServiceImpl implements ValidationService {
    
    public void save(ValidationParameter parameter) {
        System.out.println("save");
    }
    
    public void update(ValidationParameter parameter) {
    }
    
    public void delete(long id, String operator) {
        System.out.println("delete");
    }
    
}

dubbo系列二:dubbo常用功能总结(1)

在生产者dubbo-provider-web的applicationProvider.xml配置参数验证接口:

    <!--参数验证begin  -->
    <bean id="validationService" class="com.study.service.ValidationServiceImpl"/>
    <dubbo:service interface="com.study.service.ValidationService" ref="validationService"
        validation="true"/>
    <!--参数验证end  -->

在消费者dubbo-consumer-web的applicationConsumer.xml配置调用的参数验证接口

    <!--参数验证begin  -->
    <dubbo:reference id="validationService" interface="com.study.service.ValidationService"
        validation="true"/>
    <!--参数验证end  -->

在消费者dubbo-consumer-web的CommonController.java里面创建参数验证测试代码

dubbo系列二:dubbo常用功能总结(1)

    //参数验证begin
    @Autowired
    ValidationService validationService;
    
    @RequestMapping("/validation")
    public @ResponseBody String validation() {
        // Save OK
        ValidationParameter parameter = new ValidationParameter();
        parameter.setName("leeSmall");
        parameter.setEmail("[email protected]");
        parameter.setAge(50);
        parameter.setLoginDate(new Date(System.currentTimeMillis() - 1000000));
        parameter.setExpiryDate(new Date(System.currentTimeMillis() + 1000000));
        validationService.save(parameter);
        System.out.println("Validation Save OK");
        
        // Save Error
        try {
            parameter = new ValidationParameter();
            validationService.save(parameter);
            System.err.println("Validation Save ERROR");
        }
        catch (RpcException e) {
            ConstraintViolationException ve = (ConstraintViolationException)e.getCause();
            Set<ConstraintViolation<?>> violations = ve.getConstraintViolations();
            System.out.println(violations);
        }
        
        // Delete OK
        validationService.delete(2, "abc");
        System.out.println("Validation Delete OK");
        
        // Delete Error
        try {
            validationService.delete(0, "abc");
            System.err.println("Validation Delete ERROR");
        }
        catch (RpcException e) {
            ConstraintViolationException ve = (ConstraintViolationException)e.getCause();
            Set<ConstraintViolation<?>> violations = ve.getConstraintViolations();
            System.out.println(violations);
        }
        return "OK";
    }
    //参数验证end

dubbo系列二:dubbo常用功能总结(1)

在浏览器输入地址http://localhost:8081/dubbo-consumer-web/common/validation访问查看效果

生产者:

dubbo系列二:dubbo常用功能总结(1)

消费者:

dubbo系列二:dubbo常用功能总结(1)

8. 结果缓存