配置说明
启动时检查
启动时会在注册中心检查依赖的服务是否可用,不可用时会抛出异常
在消费方编写初始化容器的main方法启动(tomcat启动方式,必须访问一次action才能初始化spring)
/**
* @Program: dubbo_test2
* @Author: XiaoXing
* @Create: 2021-01-16 13:35
* @Description: 启动时检查
**/
public class TestCheckException {
public static void main(String[] args) {
//初始化spring
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/spring.xml");
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
}
<!--
关闭所有服务的启动时检查 (没有提供者时报错)
默认是true:抛异常;false:不抛异常
通常不写此配置,按照默认来
-->
<dubbo:consumer check="false" />
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %m%n
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=dubbo.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %m%n
log4j.rootLogger=error, stdout,file
超时时间
由于网络或服务端不可靠,会导致调用过程中出现不确定的阻塞状态(超时)
为了避免超时导致客户端资源(线程)挂起耗尽,必须设置超时时间
在服务提供者添加如下配置:
<!--设置超时时间为2秒,默认为1秒-->
<dubbo:provider timeout="2000"/>
可以将服务实现HelloServiceImpl.java中加入模拟的网络延迟进行测试:
@Service
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello " + name + " !!!";
}
}
超时设置2秒,而模拟的网络延迟有3秒,超出时限,报错!
配置原则:
- dubbo推荐在Provider上尽量多配置Consumer端属性:
- 作服务的提供者,比服务使用方更清楚服务性能参数,如调用的超时时间,合理的重试次数,等等
- 在Provider配置后,Consumer不配置则会使用Provider的配置值,即Provider配置可以作消费者的缺省值。
重试次数
当出现失败,自动切换并重试其它服务器,dubbo重试的缺省值是2次,我们可以自行设置
在provider提供方配置:
<!-- 消费方连接第1次不算,再来重试3次,总共重试4次 -->
<dubbo:provider timeout="2000" retries="3"/>
@Service
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
System.out.println("被调用1次");
try {
//模拟网络延迟
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello " + name + " !!!";
}
}
-
并不是所有的方法都适合设置重试次数
- 幂等方法:适合(当参数一样,无论执行多少次,结果是一样的,例如:查询,修改)
- 非幂等方法:不适合(当参数一样,执行结果不一样,例如:删除,添加)
-
单独设置某个方法
public interface HelloService { public String sayHello(String name); public String sayNo(); }
@Override public String sayNo() { System.out.println("------------no--------------"); return "no"; }
消费方接口添加sayNo()方法声明
public interface HelloService { String sayHello( String name ); public String sayNo(); }
@Controller public class HelloAction { // @Reference // 远程去服务方将service的实现类注入进来 @Autowired private HelloService helloService; @RequestMapping("/hello") @ResponseBody public String sayHi(String name){ System.out.println(name); return helloService.sayHello(name); } @RequestMapping("/no") @ResponseBody public String sayNo(){ return helloService.sayNo(); } }
消费方配置方法重试次数
<dubbo:reference interface="service.HelloService" id="helloService"> <dubbo:method name="sayHello" retries="3"></dubbo:method> <dubbo:method name="sayNo" retries="0"></dubbo:method> </dubbo:reference>
多版本
一个接口,多个(版本的)实现类,可以使用定义版本的方式引入
为HelloService接口定义两个实现类,提供者修改配置:
<!--配置多版本-->
<dubbo:service interface="service.HelloService" class="service.impl.HelloServiceImpl01" version="1.0.0"></dubbo:service>
<dubbo:service interface="service.HelloService" class="service.impl.HelloServiceImpl02" version="2.0.0"></dubbo:service>
消费者就可以根据version的版本,选择具体的服务版本
<dubbo:reference interface="service.HelloService" id="helloService" version="1.0.0">
<dubbo:method name="sayHello" retries="3"></dubbo:method>
<dubbo:method name="sayNo" retries="0"></dubbo:method>
</dubbo:reference>
注意:消费者的控制层要改为自动注入,因为@Reference注解和 dubbo:reference在这里冲突
@Controller
public class HelloAction {
// @Reference // 远程去服务方将service的实现类注入进来
@Autowired
private HelloService helloService;
}
当消费者的版本修改为 version="*",那么就会随机调用服务提供者的版本
本地存根
目前我们的分布式架构搭建起来有一个严重的问题,就是所有的操作全都是 消费者发起,由服务提供者执行
消费者动动嘴皮子却什么活都不干,这样会让提供者很累,例如简单的参数验证,消费者完全能够胜任,把合法的参数再发送给提供者执行,效率高了,提供者也没那么累了
例如:去房产局办理房屋过户,请带好自己的证件和资料,如果什么都不带,那么办理过户手续会很麻烦,得先调查你有什么贷款,有没有抵押,不动产证是不是你本人,复印资料等操作。一天肯定办不完。明天还要来。如果你能提前将这些东西准备好,办理过户,1个小时足矣,这就是“房产中介办事效率高的原因”
话不多说,先在消费者处理一些业务逻辑,再调用提供者的过程,就是“本地存根”
代码实现肯定在 消费者,创建一个HelloServiceStub类并且实现HelloService接口
注意:必须使用构造方法的方式注入
public class HelloServiceStub implements HelloService {
private HelloService helloService;
//本地存根必须以构造方法的形式注入
public HelloServiceStub(HelloService helloService){
this.helloService = helloService;
}
@Override
public String sayHello(String name) {
if (!StringUtils.isEmpty(name)){
return helloService.sayHello(name);
}
return "i am sorry!";
}
@Override
public String sayNo() {
return helloService.sayNo();
}
}
修改消费者配置
<dubbo:reference interface="service.HelloService" id="helloService" version="2.0.0" stub="stub.HelloServiceStub">
<dubbo:method name="sayHello" retries="3"></dubbo:method>
<dubbo:method name="sayNo" retries="0"></dubbo:method>
</dubbo:reference>