准备工做:html
(1)启动zookeeper做为dubbo的注册中心java
(2)新建一个maven的生产者web工程dubbo-provider-web和一个maven的消费者web工程dubbo-consumer-webnode
(3)在pom.xml文件里面引入以下依赖git
<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 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.study</groupId> <artifactId>dubbo-provider-web</artifactId> <packaging>jar</packaging> <version>0.0.1-SNAPSHOT</version> <name>dubbo-provider-web Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <spring.version>4.3.10.RELEASE</spring.version> </properties> <dependencies> <!-- 添加dubbo依赖 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.5.3</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> </exclusion> </exclusions> </dependency> <!-- 添加zk客户端依赖 --> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency> <!-- spring相关 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <!-- <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${org.springframework.version}</version> </dependency> --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>1.8.7</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> </dependency> <!-- 日志相关依赖 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.10</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.1.2</version> </dependency> <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> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>5.0.0.Alpha2</version> </dependency> </dependencies> <build> <finalName>dubbo-provider-web</finalName> </build> </project>
dubbo可使用注解在生产者端暴露服务接口和在消费端引用接口,只须要在生产者和消费者的配置文件里面配置扫描包路径便可,而不用在xml里面配置须要暴露和引用的接口程序员
扫描包路径的配置github
<!-- 扫描注解包路径,多个包用逗号分隔,不填pacakge表示扫描当前ApplicationContext中全部的类 --> <dubbo:annotation package="com.study.service" />
1.1 在生产者dubbo-provider-web和消费者dubbo-consumer-web新建一个dubbo注解测试的接口web
package com.study.service; /** * * @Description: dubbo注解测试的接口 * @author leeSmall * @date 2018年10月23日 * */ public interface AnnotationDubboTest { public String eat(String param); }
1.2 在生产者dubbo-provider-web新建一个dubbo注解测试的接口的实现类算法
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------------"; } }
1.3 在消费端dubbo-consumer-web新建一个测试的controlspring
/** * * @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"; } }
1.4 在tomcat8080和tomcat8081分别启动生产者和消费者,在浏览器输入地址http://localhost:8081/dubbo-consumer-web/common/annotationdubbo访问查看效果apache
生产者端:
浏览器:
Dubbo缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止Spring初始化完成,以便上线时,能及早发现问题,默认 check="true" 。
能够经过 check="false" 关闭检查,好比,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。
另外,若是你的Spring容器是懒加载的,或者经过API编程延迟引用服务,请关闭 check,不然服务临时不可用时,会抛出异常,拿到null引用,若是 check="false" ,老是会返回引用,当服务恢复时,能自动连上。
关闭某个服务的启动时检查 (没有提供者时报错):
<dubbo:reference interface="com.foo.BarService" check="false" />
关闭全部服务的启动时检查 (没有提供者时报错):
<dubbo:consumer check="false" />
失败自动切换,缺省值,当出现失败,重试其它服务器。一般用于读操做,但重试会带来更长延迟。可经过 retries="2" 来设置重试次数(不含第一次)。
配置以下:
生产者:
<dubbo:service retries="2" />
消费者:
<dubbo:reference retries="2" />
消费者具体到调用生产者的哪一个方法:
<dubbo:reference>
<dubbo:method name="findFoo" retries="2" />
</dubbo:reference>
快速失败,只发起一次调用,失败当即报错。一般用于非幂等性的写操做,好比新增记录。
配置以下:
生产者:
<dubbo:service cluster="failfast" />
消费者:
<dubbo:reference cluster="failfast" />
失败安全,出现异常时,直接忽略。一般用于写入审计日志等操做。
配置以下:
生产者:
<dubbo:service cluster="failsafe" />
消费者:
<dubbo:reference cluster="failsafe" />
失败自动恢复,后台记录失败请求,定时重发。一般用于消息通知操做。
配置以下:
生产者:
<dubbo:service cluster="failback" />
消费者:
<dubbo:reference cluster="failback" />
并行调用多个服务器,只要一个成功即返回。一般用于实时性要求较高的读操做,但须要浪费更多服务资源。可经过 forks="2" 来设置最大并行数。
配置以下:
生产者:
<dubbo:service cluster=“forking" />
消费者:
<dubbo:reference cluster=“forking" />
广播调用全部提供者,逐个调用,任意一台报错则报错 。一般用于通知全部提供者更新缓存或日志等本地资源信息。
配置以下:
生产者:
<dubbo:service cluster="broadcast" />
消费者:
<dubbo:reference cluster="broadcast" />
随机,按权重设置随机几率。
在一个截面上碰撞的几率高,但调用量越大分布越均匀,并且按几率使用权重后也比较均匀,有利于动态调整提供者权重。
配置以下:
<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: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>
一致性 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: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: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>
当一个接口有多个实现时,能够用group区分要调用的服务。
在生产者dubbo-provider-web和消费者dubbo-consumer-web分别新建一个接口
package com.study.test.service; public interface DubboTestService { public String eat(String param); }
在生产者dubbo-provider-web新建两个DubboTestService接口的实现类
实现类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 ------------"; } }
实现类2:
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-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里面建立服务分组测试代码
//服务分组示例begin @Autowired @Qualifier("dubboTestServiceImpl1") DubboTestService dubboService1; @Autowired @Qualifier("dubboTestServiceImpl2") DubboTestService dubboService2; @RequestMapping("/dubboTest") public @ResponseBody String dubboTest() { dubboService1.eat("服务分组示例!"); dubboService2.eat("服务分组示例!"); return "dubboTest"; } //服务分组示例end
在浏览器输入地址http://localhost:8081/dubbo-consumer-web/common/dubboTest访问查看效果
生产者:
浏览器:
在生产者dubbo-provider-web和消费者dubbo-consumer-web分别新建一个接口
package com.study.service; public interface UserService { public String login(String param); }
在生产者dubbo-provider-web新建两个UserService接口的实现类
实现类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 "用户已经登陆成功!·~~~~~~~~~~~~~~~~~~"; } }
实现类2:
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-consumer-web的CommonController.java里面建立服务分组测试代码
//服务分组注解实现示例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
在浏览器输入地址http://localhost:8081/dubbo-consumer-web/common/grouplogin1访问查看效果
生产者:
消费者:
当一个接口实现出现不兼容升级时,能够用版本号过渡,版本号不一样的服务相互间不引用。
能够按照如下的步骤进行版本迁移:
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="*" />
在生产者dubbo-provider-web和消费者dubbo-consumer-web的pom.xml里面分别引入以下依赖:
<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-provider-web和消费者dubbo-consumer-web分别新建一个参数验证接口和一个参数验证明体
参数验证接口:
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 { } }
参数验证明体:
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-provider-web新建ValidationService接口的实现类
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-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里面建立参数验证测试代码
//参数验证begin @Autowired ValidationService validationService; @RequestMapping("/validation") public @ResponseBody String validation() { // Save OK ValidationParameter parameter = new ValidationParameter(); parameter.setName("leeSmall"); parameter.setEmail("leeSmall@qq.com"); 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
在浏览器输入地址http://localhost:8081/dubbo-consumer-web/common/validation访问查看效果
生产者:
消费者:
缓存类型
lru 基于最近最少使用原则删除多余缓存,保持最热的数据被缓存。
LRU的缺省cache.size为1000,执行1001次,会把最开始请求的缓存结果清除掉
在生产者dubbo-provider-web和消费者dubbo-consumer-web分别新建一个接口
package com.study.service; /** * * @Description: 结果缓存接口 * @author leeSmall * @date 2018年10月24日 * */ public interface CacheService { String findCache(String id); }
在生产者dubbo-provider-web新建CacheService接口的实现类
package com.study.service; import java.util.concurrent.atomic.AtomicInteger; /** * * @Description: 结果缓存接口实现类 * @author leeSmall * @date 2018年10月24日 * */ public class CacheServiceImpl implements CacheService { private final AtomicInteger i = new AtomicInteger(); public String findCache(String id) { System.out.println("request: " + id + ", response: " + i.getAndIncrement()); return "request: " + id + ", response: " + i.getAndIncrement(); } }
在生产者dubbo-provider-web的applicationProvider.xml配置结果缓存接口
<!--结果缓存begin --> <bean id="cacheService" class="com.study.service.CacheServiceImpl"/> <dubbo:service interface="com.study.service.CacheService" ref="cacheService"/> <!--结果缓存end -->
在消费者dubbo-consumer-web的applicationConsumer.xml配置调用的缓存接口
<!--结果缓存begin --> <dubbo:reference id="cacheService" interface="com.study.service.CacheService" cache="lru"/> <!--结果缓存end -->
在消费者dubbo-consumer-web的CommonController.java里面建立缓存接口测试代码
//结果缓存begin @Autowired CacheService cacheService; @RequestMapping("/cache") public @ResponseBody String cache() { // 测试缓存生效,屡次调用返回一样的结果。(服务器端自增加返回值) String fix = null; for (int i = 0; i < 5; i++) { String result = cacheService.findCache("0"); if (fix == null || fix.equals(result)) { System.out.println("OK: " + result); } else { System.err.println("ERROR: " + result); } fix = result; try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } // LRU的缺省cache.size为1000,执行1001次,会把第一次请求的缓存结果清除掉 for (int n = 0; n < 1001; n++) { String pre = null; for (int i = 0; i < 10; i++) { String result = cacheService.findCache(String.valueOf(n)); if (pre != null && !pre.equals(result)) { System.err.println("ERROR: " + result); } pre = result; } } // 测试LRU有移除最开始的一个缓存项 String result = cacheService.findCache("0"); if (fix != null && !fix.equals(result)) { System.out.println("OK: " + result); } else { System.err.println("ERROR: " + result); } return "OK"; } //结果缓存end
在浏览器输入地址http://localhost:8081/dubbo-consumer-web/common/cache访问查看效果:
测试缓存生效,屡次调用返回一样的结果。(服务器端自增加返回值):
生产者:
消费者:
LRU的缺省cache.size为1000,执行1001次,会把第一次请求的缓存结果清除掉:
生产者:
测试LRU有移除最开始的一个缓存项:
生产者:
消费者:
泛化接口调用方式主要用于客户端没有API接口及模型类元的状况,参数及返回值中的全部POJO均用 Map表示,一般用于框架集成,好比:实现一个通用的服务测试框架,可经过GenericService 调用全部服务实现。
泛化调用就是服务消费者端由于某种缘由并无该服务接口,这个缘由有不少,好比是跨语言的,一个PHP工程师想调用某个java接口,他并不能按照你约定,去写一个个的接口,Dubbo并非跨语言的RPC框架,但并非不能解决这个问题,这个PHP程序员搭建了一个简单的java web项目,引入了dubbo的jar包,使用dubbo的泛化调用,而后利用web返回json,这样也能完成跨语言的调用。泛化调用的好处之一就是这个了。
好了,简而言之,泛化调用,最直接的表现就是服务消费者不须要有任何接口的实现,就能完成服务的调用。
这个功能通常不用,由于代码的可读性不好
在生产者dubbo-provider-web新建一个接口:
package com.study.service; /** * * @Description: 泛化调用接口 * @author leeSmall * @date 2018年10月23日 * */ public interface DemoService { String eat(Long id); }
在生产者dubbo-provider-web新建两个DemoService接口的实现类
package com.study.service; /** * * @Description: 泛化调用接口实现类 * @author leeSmall * @date 2018年10月23日 * */ public class DemoServiceImpl implements DemoService { public String eat(Long id) { System.out.println("泛化调用"); return "泛化调用" + id; } }
在生产者dubbo-provider-web的applicationProvider.xml配置泛化调用接口
<!--泛化调用begin--> <dubbo:service interface="com.study.service.DemoService" ref="demoService" protocol="dubbo"/> <bean id="demoService" class="com.study.service.DemoServiceImpl"/> <!--泛化调用end-->
在消费者dubbo-consumer-web的applicationConsumer.xml配置调用的泛化调用接口
<!--泛化调用begin --> <dubbo:reference id="demoService" interface="com.study.service.DemoService" generic="true"/> <!--泛化调用end -->
在消费者dubbo-consumer-web的CommonController.java里面建立泛化调用测试代码
//泛化调用begin @RequestMapping("/fanhua") public @ResponseBody String fanhuayinyong() { GenericService demoService = (GenericService)applicationContext.getBean("demoService"); Object result = demoService.$invoke("eat", new String[] { "java.lang.Long" }, new Object[]{ 1L }); System.out.println(result); return "OK"; } //泛化调用end
在浏览器输入地址http://localhost:8081/dubbo-consumer-web/common/fanhua访问查看效果
生产者:
消费者:
泛接口实现方式主要用于服务器端没有API接口及模型类元的状况,参数及返回值中的全部POJO均用Map表示,一般用于框架集成,好比:实现一个通用的远程服务Mock框架,可经过实现GenericService接口处理全部服务请求。
在生产者dubbo-provider-web新建dubbo提供的泛化接口的实现类:
package com.study.service; import com.alibaba.dubbo.rpc.service.GenericException; import com.alibaba.dubbo.rpc.service.GenericService; /** * * @Description: dubbo提供的泛化接口的实现类 * @author leeSmall * @date 2018年10月24日 * */ public class MyGenericService implements GenericService { public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException { System.out.println("泛化调用实现!"); return "泛化调用实现"; } }
在生产者dubbo-provider-web的applicationProvider.xml配置泛化接口的实现类
<!--实现泛化调用begin --> <bean id="genericService" class="com.study.service.MyGenericService" /> <dubbo:service interface="com.alibaba.dubbo.rpc.service.GenericService" ref="genericService" /> <!--实现泛化调用end -->
在消费者dubbo-consumer-web的applicationConsumer.xml配置调用的泛化接口的实现
<!--实现泛化调用begin --> <dubbo:reference id="genericService" interface="com.alibaba.dubbo.rpc.service.GenericService"/> <!--实现泛化调用end -->
在消费者dubbo-consumer-web的CommonController.java里面建立泛化接口的实现测试代码
//实现泛化调用begin @RequestMapping("/fanhuashixian") public @ResponseBody String fanhuashixian() { GenericService barService = (GenericService)applicationContext.getBean("genericService"); Object result = barService.$invoke("login", new String[] {"java.lang.String"}, new Object[] {"World"}); System.out.println(result); return "OK"; } //实现泛化调用end
在浏览器输入地址http://localhost:8081/dubbo-consumer-web/common/fanhuashixian访问查看效果
生产者:
消费者:
回声测试用于检测服务是否可用,回声测试按照正常请求流程执行,可以测试整个调用是否通畅,可用于监控。
全部服务自动实现EchoService接口,只需将任意服务引用强制转型为EchoService,便可使用。
直接使用第8个功能点(8.结果缓存)的接口进行回声测试的实现
在消费者dubbo-consumer-web的CommonController.java里面建立回声测试的测试代码:
//回声测试begin @RequestMapping("/huisheng") public @ResponseBody String huisheng() { CacheService barService = (CacheService)applicationContext.getBean("cacheService"); EchoService echoService = (EchoService)barService; // 强制转型为EchoService // 回声测试可用性 String status = (String)echoService.$echo("OK"); if(status.equals("OK")) { System.out.println("缓存接口服务可用"); } assert (status.equals("OK")); return "OK"; } //回声测试end
在浏览器输入地址http://localhost:8081/dubbo-consumer-web/common/huisheng访问查看效果
消费者:
基于NIO的非阻塞实现并行调用,客户端不须要启动多线程便可完成并行调用多个远程服务,相对多线程开销较小。
在生产者dubbo-provider-web和消费者dubbo-consumer-web分别新建一个接口:
package com.study.service; /** * * @Description: 异步调用接口 * @author leeSmall * @date 2018年10月24日 * */ public interface AsyncService { String sayHello(String name); }
在生产者dubbo-provider-web新建AsyncService接口的实现类
package com.study.service; /** * * @Description: 异步调用接口实现类 * @author leeSmall * @date 2018年10月24日 * */ public class AsyncServiceImpl implements AsyncService { public String sayHello(String name) { for (int i = 0; i < 5; i++) { System.out.println("async provider received: " + name); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } return "hello, " + name; } }
在生产者dubbo-provider-web的applicationProvider.xml配置异步调用接口
<!--异步调用begin --> <bean id="asyncServiceImpl" class="com.study.service.AsyncServiceImpl"/> <dubbo:service interface="com.study.service.AsyncService" ref="asyncServiceImpl"/> <!--异步调用end -->
在消费者dubbo-consumer-web的applicationConsumer.xml配置调用的异步调用接口
<!--异步调用begin --> <dubbo:reference id="asyncServiceImpl" interface="com.study.service.AsyncService" timeout="1200000"> <dubbo:method name="sayHello" async="true"/> </dubbo:reference> <!--异步调用end -->
在消费者dubbo-consumer-web的CommonController.java里面建立异步调用测试代码
//异步调用begin @Autowired AsyncService asyncService; @RequestMapping("/async") public @ResponseBody String async() { String result = asyncService.sayHello("我是异步调用客户端"); System.out.println(result); // 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future Future<String> fooFuture = RpcContext.getContext().getFuture(); // 若是result已返回,直接拿到返回值,不然线程wait住,等待result返回后,线程会被notify唤醒 try { //调用get方法会阻塞在这里直到拿到结果 result = fooFuture.get(); System.out.println(result); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } return "OK"; } //异步调用end
在浏览器输入地址http://localhost:8081/dubbo-consumer-web/common/async访问查看效果:
生产者:
消费者:
参数回调方式与调用本地callback或listener相同,只须要在Spring的配置文件中声明哪一个参数是callback 类型便可。Dubbo将基于长链接生成反向代理,这样就能够从服务器端调用客户端逻辑。适用于服务端完成某个动做之后通知客户端
在生产者dubbo-provider-web和消费者dubbo-consumer-web分别新建一个参数回调监听接口和参数回调接口
参数回调监听接口:
package com.study.callback; /** * * @Description: 参数回调监听接口 * @author leeSmall * @date 2018年10月25日 * */ public interface CallbackListener { void changed(String msg); }
参数回调接口:
package com.study.callback; /** * * @Description: 参数回调接口 * @author leeSmall * @date 2018年10月25日 * */ public interface CallbackService { void addListener(String key, CallbackListener listener); }
在生产者dubbo-provider-web新建CallbackService接口的实现类
package com.study.callback; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * * @Description: 参数回调接口实现类 * @author leeSmall * @date 2018年10月25日 * */ public class CallbackServiceImpl implements CallbackService { private final Map<String, CallbackListener> listeners = new ConcurrentHashMap<String, CallbackListener>(); public CallbackServiceImpl() { Thread t = new Thread(new Runnable() { public void run() { while (true) { try { for (Map.Entry<String, CallbackListener> entry : listeners.entrySet()) { try { entry.getValue() .changed(getChanged(entry.getKey())); } catch (Throwable t) { listeners.remove(entry.getKey()); } } Thread.sleep(5000); // 定时触发变动通知 } catch (Throwable t) { // 防护容错 t.printStackTrace(); } } } }); t.setDaemon(true); t.start(); } public void addListener(String key, CallbackListener listener) { listeners.put(key, listener); listener.changed(getChanged(key)); // 发送变动通知 } private String getChanged(String key) { return "Changed: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); } }
在生产者dubbo-provider-web的applicationProvider.xml配置参数回调接口
<!--参数回调begin --> <bean id="callbackService" class="com.study.callback.CallbackServiceImpl"/> <dubbo:service interface="com.study.callback.CallbackService" ref="callbackService" connections="1" callbacks="1000"> <dubbo:method name="addListener"> <dubbo:argument index="1" callback="true"/> <!--也能够经过指定类型的方式--> <!--<dubbo:argument type="com.demo.CallbackListener" callback="true" />--> </dubbo:method> </dubbo:service> <!--参数回调end -->
在消费者dubbo-consumer-web的applicationConsumer.xml配置调用的参数回调接口
<!--参数回调begin --> <dubbo:reference id="callbackService" interface="com.study.callback.CallbackService"/> <!--参数回调end -->
在消费者dubbo-consumer-web的CommonController.java里面建立参数回调接口测试代码
//参数回调begin @Autowired CallbackService callbackService; @RequestMapping("/callback") public @ResponseBody String callback() { callbackService.addListener("foo.bar", new CallbackListener() { public void changed(String msg) { System.out.println("callback1:" + msg); } }); return "OK"; } //参数回调end
在浏览器输入地址http://localhost:8081/dubbo-consumer-web/common/callback访问查看效果:
生产者:
消费者:
在调用以前、调用以后、出现异常时,会触发 oninvoke、onreturn、onthrow 三个事件,能够配置当事件发生时,通知哪一个类的哪一个方法 。
在生产者dubbo-provider-web和消费者dubbo-consumer-web分别新建一个接口
package com.study.event; /** * * @Description: 事件通知接口参与接口 * @author leeSmall * @date 2018年10月25日 * */ public interface Common { public String eat(String param); }
在生产者dubbo-provider-web新建Common接口的实现类
package com.study.event; /** * * @Description: 事件通知接口参与接口实现类 * @author leeSmall * @date 2018年10月25日 * */ public class CommonImpl implements Common { public String eat(String param) { System.out.println("CommonImpl eat"); return "CommonImpl eat"; } }
在生产者dubbo-provider-web的applicationProvider.xml配置事件通知接口参与接口
<!-- 事件通知接口参与接口begin --> <bean id="commonImpl" class="com.study.event.CommonImpl"/> <dubbo:service interface="com.study.event.Common" ref="commonImpl"/> <!-- 事件通知接口参与接口end -->
在消费者dubbo-consumer-webl建立事件通知接口
package com.study.event; /** * * @Description: 事件通知接口 * @author leeSmall * @date 2018年10月25日 * */ public interface Notify { //调用以前 public void oninvoke(String name); //调用以后 public void onreturn(String msg); // 出现异常 public void onthrow(Throwable ex); }
在消费者dubbo-consumer-web建立事件通知接口实现类
package com.study.event; /** * * @Description: 事件通知接口实现类 * @author leeSmall * @date 2018年10月25日 * */ public class NotifyImpl implements Notify { //调用以前 public void oninvoke(String msg) { System.out.println("======oninvoke======, param: " + msg); } //调用以后 public void onreturn(String msg) { System.out.println("======onreturn======, param: " + msg); } // 出现异常 public void onthrow(Throwable ex) { System.out.println("======onthrow======, param: " + ex); } }
在消费者dubbo-consumer-web的applicationConsumer.xml配置调用事件通知接口参与接口和事件通知接口
<!--事件通知begin --> <bean id ="demoCallback" class = "com.study.event.NotifyImpl" /> <dubbo:reference id="commonImpl" interface="com.study.event.Common" > <dubbo:method name="eat" async="false" oninvoke="demoCallback.oninvoke" onreturn = "demoCallback.onreturn" onthrow= "demoCallback.onthrow" /> </dubbo:reference> <!--事件通知end -->
在消费者dubbo-consumer-web的CommonController.java里面建立事件通知接口测试代码
//事件通知begin @Autowired Common common; @RequestMapping("/event") public @ResponseBody String event() { String result = common.eat("jdksk"); System.out.println(result); return "OK"; } //事件通知end
在浏览器输入地址http://localhost:8081/dubbo-consumer-web/common/cache访问查看效果:
生产者:
消费者:
远程服务后,客户端一般只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑,好比:作 ThreadLocal缓存,提早验证参数,调用失败后伪造容错数据等等,此时就须要在API中带上Stub,客户端生成Proxy实例,会把Proxy经过构造函数传给Stub ,而后把Stub暴露给用户,Stub能够决定要不要去调Proxy。
在生产者dubbo-provider-web和消费者dubbo-consumer-web分别新建一个接口
package com.study.stub; /** * * @Description: 本地存根接口 * @author leeSmall * @date 2018年10月25日 * */ public interface StubService { String stub(String param); }
在生产者dubbo-provider-web新建StubService接口的实现类
package com.study.stub; /** * * @Description: 本地存根接口实现类 * @author leeSmall * @date 2018年10月25日 * */ public class StubServiceImpl implements StubService { public String stub(String param) { System.out.println("provider StubServiceImpl stub"); return "provider StubServiceImpl stub"; } }
在生产者dubbo-provider-web的applicationProvider.xml配置本地存根接口
<!--本地存根begin --> <bean id="stubServiceImpl" class="com.study.stub.StubServiceImpl"/> <dubbo:service interface="com.study.stub.StubService" ref="stubServiceImpl"/> <!--本地存根end -->
在消费者dubbo-consumer-web建立本地存根Proxy实例
package com.study.stub; /** * * @Description: 本地存根Proxy实例 * @author leeSmall * @date 2018年10月25日 * */ public class LocalStubServiceProxy implements StubService { private StubService stubService; public LocalStubServiceProxy(StubService stubService) { this.stubService = stubService; } public String stub(String arg0) { System.out.println("我是localstub,我就至关于一个过滤器,在代理调用远程方法的时候,我先作一下拦截工做"); try { return stubService.stub("xxx"); } catch (Exception e) { System.out.println("远程调用出现异常了,我是本地stub,我要对远程服务进行假装,达到服务降级的目的"); return "远程调用出现异常了,我是本地stub,我要对远程服务进行假装,达到服务降级的目的"; } } }
在消费者dubbo-consumer-web的applicationConsumer.xml配置本地存根接口和stub对应的本地存根Proxy实例
<!--本地存根begin --> <dubbo:reference id="stubServiceImpl" interface="com.study.stub.StubService" stub="com.study.stub.LocalStubServiceProxy"/> <!--本地存根end -->
在消费者dubbo-consumer-web的CommonController.java里面建立本地存根接口测试代码
//本地存根begin @Autowired StubService stub; @RequestMapping("/stub") public @ResponseBody String stub() { String result = stub.stub("eee"); System.out.println(result); return "OK"; } //本地存根end
在浏览器输入地址http://localhost:8081/dubbo-consumer-web/common/stub访问查看效果:
生产者:
消费者:
本地假装 一般用于服务降级,好比某验权服务,当服务提供方所有挂掉后,客户端不抛出异常,而是经过Mock数据返回受权失败。
在spring配置文件中按如下方式配置:
<dubbo:service interface="com.foo.BarService" mock="com.foo.BarServiceMock" />
1)Mock是Stub的一个子集,便于服务提供方在客户端执行容错逻辑,因常常须要在出现RpcException(好比网络失败,超时等)时进行容错,而在出现业务异常(好比登陆用户名密码错误)时不须要容错,若是用Stub,可能就须要捕获并依赖RpcException类,而用Mock就能够不依赖RpcException,由于它的约定就是只有出现RpcException时才执行。
2)在interface旁放一个Mock实现,它实现BarService接口,并有一个无参构造函数
在生产者dubbo-provider-web和消费者dubbo-consumer-web分别新建一个接口
package com.study.mock; /** * * @Description: 本地假装接口 * @author leeSmall * @date 2018年10月25日 * */ public interface MockService { String mock(String param); }
在生产者dubbo-provider-web新建MockService接口的实现类
package com.study.mock; /** * * @Description: 本地假装接口实现类 * @author leeSmall * @date 2018年10月25日 * */ public class MockServiceImpl implements MockService { public String mock(String param) { System.out.println("provider MockServiceImpl mock"); return "provider MockServiceImpl mock"; } }
在生产者dubbo-provider-web的applicationProvider.xml配置本地假装接口
<!--本地假装begin --> <bean id="mockServiceImpl" class="com.study.mock.MockServiceImpl"/> <dubbo:service interface="com.study.mock.MockService" ref="mockServiceImpl"/> <!--本地假装end -->
在消费者dubbo-consumer-web建立本地假装代理实例
package com.study.mock; /** * * @Description: 本地假装代理实例 * @author leeSmall * @date 2018年10月25日 * */ public class LocalMockProxyService implements MockService { public String mock(String arg0) { System.out.println("local mock 作一下容错处理,这个就是服务降级"); return "local mock 作一下容错处理,这个就是服务降级"; } }
在消费者dubbo-consumer-web的applicationConsumer.xml配置调用的本地假装接口和本地假装代理实例
<!--本地假装begin --> <dubbo:reference id="mockServiceImpl" interface="com.study.mock.MockService" mock="com.study.mock.LocalMockProxyService"/> <!--本地假装end -->
在消费者dubbo-consumer-web的CommonController.java里面建立本地假装接口测试代码
//本地假装begin @Autowired MockService mock; @RequestMapping("/mock") public @ResponseBody String mock() { String result = mock.mock("vvvv"); System.out.println(result); return "OK"; } //本地假装end
在浏览器输入地址http://localhost:8081/dubbo-consumer-web/common/mock访问查看效果:
生产者:
消费者:
停掉生产者,再次在浏览器访问查看效果:
消费者:
延迟到Spring初始化完成后,再暴露服务,规避spring的加载死锁问题
生产者单个服务接口配置:
<dubbo:service delay="-1" />
生产者全局服务接口配置:
<dubbo:provider deplay=”-1” />
源码实现方式:ApplicationListener<ContextRefreshEvent> 监控ContextRefreshEvent事件
服务端配置:
限制com.foo.BarService的每一个方法,服务器端并发执行(或占用线程池线程数)不能超过10个:
<dubbo:service interface="com.foo.BarService" executes="10" />
限制com.foo.BarService的sayHello方法,服务器端并发执行(或占用线程池线程数)不能超过10个:
<dubbo:service interface="com.foo.BarService"> <dubbo:method name="sayHello" executes="10" /> </dubbo:service>
客户端配置:
限制com.foo.BarService的每一个方法,每一个客户端并发执行(或占用链接的请求数)不能超过10个:
<dubbo:service interface="com.foo.BarService" actives="10" /> <dubbo:reference interface="com.foo.BarService" actives="10" />
限制com.foo.BarService的sayHello方法,每一个客户端并发执行(或占用链接的请求数)不能超过10个:
<dubbo:service interface="com.foo.BarService"> <dubbo:method name="sayHello" actives="10" /> </dubbo:service> <dubbo:reference interface="com.foo.BarService"> <dubbo:method name="sayHello" actives="10" /> </dubbo:service>
若是<dubbo:service>和<dubbo:reference>都配了actives, <dubbo:reference>优先
服务端链接控制
限制服务器端接受的链接不能超过10个
<dubbo:provider protocol="dubbo" accepts="10" /> <dubbo:protocol name="dubbo" accepts="10" />
客户端链接控制
限制客户端服务使用链接不能超过10个
<dubbo:reference interface="com.foo.BarService" connections="10" /> <dubbo:service interface="com.foo.BarService" connections="10" />
延迟链接
延迟链接用于减小长链接数。当有调用发起时,再建立长链接。
<dubbo:protocol name="dubbo" lazy="true" />
注意:该配置只对使用长链接的dubbo协议生效。
粘滞链接
粘滞链接用于有状态服务,尽量让客户端老是向同一提供者发起调用,除非该提供者挂了,再连另外一台。
粘滞链接将自动开启延迟链接,以减小长链接数。
<dubbo:protocol name="dubbo" sticky="true" />
经过令牌验证在注册中心控制权限,以决定要不要下发令牌给消费者,能够防止消费者绕过注册中心访问提供者,另外经过注册中心可灵活改变受权方式,而不需修改或升级提供者
能够在生产者(客户端不须要配置token,只须要从注册中心获取服务时获取便可)全局设置开启令牌验证:
<!--随机token令牌,使用UUID生成--> <dubbo:provider interface="com.foo.BarService" token="true" /> <!--固定token令牌,至关于密码--> <dubbo:provider interface="com.foo.BarService" token="123456" />
路由规则:决定一次dubbo服务调用的目标服务器,分为条件路由规则和脚本路由规则,而且支持可扩展。
向注册中心写入路由规则的操做一般由监控中心或治理中心的页面完成
示例:
registry.register(URL.valueOf("condition://0.0.0.0/com.foo.BarService?category=routers
&dynamic=false&rule=" + URL.encode("host = 10.20.153.10 => host = 10.20.153.11") + "));
示例属性说明:
condition:// 表示路由规则的类型,支持条件路由规则和脚本路由规则,可扩展,必填。
0.0.0.0 表示对全部 IP 地址生效,若是只想对某个 IP 的生效,请填入具体 IP,必填。
com.foo.BarService 表示只对指定服务生效,必填。
category=routers 表示该数据为动态配置类型,必填。
dynamic=false 表示该数据为持久数据,当注册方退出时,数据依然保存在注册中心,必填。
enabled=true 覆盖规则是否生效,可不填,缺省生效。
force=false 当路由结果为空时,是否强制执行,若是不强制执行,路由结果为空的路由规则将自动失效,可不填,缺省为 flase 。
runtime=false 是否在每次调用时执行路由规则,不然只在提供者地址列表变动时预先执行并缓存结果,调用时直接从缓存中获取路由结果。若是用了参数路由,必须设为true ,须要注意设置会影响调用的性能,可不填,缺省为flase。
priority=1 路由规则的优先级,用于排序,优先级越大越靠前执行,可不填,缺省为0。
rule=URL.encode("host = 10.20.153.10 => host = 10.20.153.11") 表示路由规则的内容,必填。
基于条件表达式的路由规则
示例:host = 10.20.153.10 => host = 10.20.153.11
示例说明:
=> 以前的为消费者匹配条件,全部参数和消费者的 URL 进行对比,当消费者知足匹配
条件时,对该消费者执行后面的过滤规则。
=> 以后为提供者地址列表的过滤条件,全部参数和提供者的 URL 进行对比,消费者最终只拿到过滤后的地址列表。
若是匹配条件为空,表示对全部消费方应用,如:=> host != 10.20.153.11
若是过滤条件为空,表示禁止访问,如:host = 10.20.153.10 =>
表达式参数支持:
服务调用信息,如:method,argument等,暂不支持参数路由
URL自己的字段,如:protocol,host,port等,以及URL上的全部参数,如:application,organization等
条件支持:
等号 = 表示"匹配",如: host = 10.20.153.10
不等号 != 表示"不匹配",如: host != 10.20.153.10
值支持:
以逗号 , 分隔多个值,如: host != 10.20.153.10,10.20.153.11
以星号 * 结尾,表示通配,如: host != 10.20.*
以美圆符 $ 开头,表示引用消费者参数,如: host = $host
白名单:
host != 10.20.153.10,10.20.153.11 =>
黑名单:
host = 10.20.153.10,10.20.153.11 =>
读写分离:
method = find*,list*,get*,is* => host = 172.22.3.94,172.22.3.95,172.22.3.96
method != find*,list*,get*,is* => host = 172.22.3.97,172.22.3.98
先后台分离:
application = bops => host = 172.22.3.91,172.22.3.92,172.22.3.93
application != bops => host = 172.22.3.94,172.22.3.95,172.22.3.96
能够经过服务降级功能临时屏蔽某个出错的非关键服务,并定义降级后的返回策略。
向注册中心写入动态配置覆盖规则:
mock=force:return+null 表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。
还能够改成 mock=fail:return+null 表示消费方对该服务的方法调用在失败后,再返回null值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。
参考文章:
dubbo官方文档:http://dubbo.apache.org/zh-cn/docs/user/quick-start.html
Dubbo基本特性之泛化调用:https://www.cnblogs.com/flyingeagle/p/8908317.html