Dubbo配置_2
配置的官方网址http://dubbo.apache.org/zh-cn/docs/user/configuration/xml.html
1、配置原则
1 .properties加载顺序
1-1dubbo.properties 加载顺序 优先1,其次2 ,最后3
上面图中的顺序对应下面的3中情况
1.JVM 启动 -D 参数优先,这样可以使用户在部署和启动时进行参数重写,比如在启动时需改变协议的端口。
2.XML 次之,如果在 XML 中有配置,则 dubbo.properties 中的相应配置项无效。相当于和spring整合项目里的provider.xml,与springboot整合的application.properties文件
3.Properties 最后,相当于缺省值,只有 XML 没有配置时,dubbo.properties 的相应配置项才会生效,通常用于共享公共配置,比如应用名
为了便于测试效果,我们在boot-user-service-provider项目中创建一个dubbo.properties文件
我们只修改对应的端口号,便于区分
1.虚拟机参数 -Ddubbo.protocol.port=20880
2.application.properties文件中的修改
3.dubbo.properties文件中的配置 只需配置一行端口号
dubbo.protocol.port=20882
运行启动程序 开后台日志信息
1.设计虚拟机参数 ,对应的两个配置文件也配置好了,优先加载的20880 虚拟机参数是优先
2. 删除虚拟机参数,看另外两个的顺序,先加载application.properties 文件
3.注释掉application.properties文件中的配置 ,最后加载的是dubbo.properties文件
2、启动时检查
Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题,默认 check="true"
。
可以通过 check="false"
关闭检查,调用的时候才回去检查调用的服务是否启动,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。
另外,如果你的 Spring 容器是懒加载的,或者通过 API 编程延迟引用服务,请关闭 check,否则服务临时不可用时,会抛出异常,拿到 null 引用,如果 check="false"
,总是会返回引用,当服务恢复时,能自动连上。
如图即使我们注释掉了user-service-consumer 项目中的条用的代码,依然是报错的
当我们修改配置comsumer.xml文件中 增加check="false" 这个配置再看控制台的消息
<!-- 调用的服务 -->
<dubbo:reference id="userService" interface="com.atguigu.gmail.service.UserService"
check="false"/>
可以看到增加一段配置后控制台没有报错了
这个只是一个消费服务这的服务不检查,如果实际的项目的服务消费者比较多,我们一一的配置比较麻烦,还有一个中同一配置消费服务不检查的配置还是在consumer.xml文件中 增加,效果和上面的是一样
<!-- 配置当前消费者同一规则:所有的服务都不检查 -->
<dubbo:consumer check="false"></dubbo:consumer>
3、超时时间
由于网络或服务端不可靠,会导致调用出现一种不确定的中间状态(超时)。为了避免超时导致客户端资源(线程)挂起耗尽,必须设置超时时间。timeout 设置超时时间
我们以user-serivce-provider 和user-service-consumer项目为测试时案例
consumer.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://dubbo.apache.org/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://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<context:component-scan base-package="com.atguigu.gmail.service.impl"></context:component-scan>
<!-- 服务名称 -->
<dubbo:application name="order-service-consumer"/>
<!-- 注册中心地址 -->
<dubbo:registry address="zookeeper://10.5.96.48:2181"/>
<!-- 调用的服务 -->
<!-- timeout="0" 超时 默认是1000豪秒-->
<dubbo:reference interface="com.atguigu.gmail.service.UserService"
id="userService"/>
<!-- 配置当前消费者同一规则:所有的服务都不检查 -->
<dubbo:consumer check="false"></dubbo:consumer>
<!-- 配置监控中心 -->
<!-- 下面的两种都可以 -->
<!-- ① 是默认配置自动发现 -->
<!-- ② 直连监控中心-->
<!-- <dubbo:monitor protocol="registry"></dubbo:monitor> -->
<dubbo:monitor address="127.0.0.1:7070"></dubbo:monitor>
</beans>
我们让服务提供者睡4秒
package com.atguigu.gmail.service.impl;
import java.util.Arrays;
import java.util.List;
import com.atguigu.gmail.bean.UserAddress;
import com.atguigu.gmail.service.UserService;
public class UserServiceImpl implements UserService {
public List<UserAddress> getUserAddressList(String userId) {
UserAddress address1 = new UserAddress(1,"东长安街89号","1","李老师","13278977","1");
UserAddress address2 = new UserAddress(2,"西长安街89号","1","李老师","13278977","1");
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return Arrays.asList(address1,address2);
}
}
运运行服务的提供者,先注册到注册中心,在运行服务的消费者,代码前面都写过就不贴了,
报错,我们并没有设置超时时间,可是依然报超时1000ms ,这是因为timeout的超时时间默认是1000豪秒
第二次我们设置超时时间是5000ms
<!-- 调用的服务 -->
<!-- timeout="0" 超时 -->
<dubbo:reference interface="com.atguigu.gmail.service.UserService"
id="userService" timeout="5000"/>
看运行结果,这次就补贴图了,可以自己验证,可以调用成功
超时的优先级别图,有上到下优先级别,先方法①,后接口②,全局最后③ ,每个级别都是对应的消费方优先
服务消费者还可以这样配置超时时间,指定方法名,和方法的超时时间 ,和全局的配置
<!-- 调用的服务 -->
<!-- timeout="0" 超时 -->
<dubbo:reference interface="com.atguigu.gmail.service.UserService"
id="userService" timeout="5000">
<!-- 可以指定方法名,也可以指定超时时间 -->
<dubbo:method name="getUserAddressList" timeout="1000"></dubbo:method>
</dubbo:reference>
<!-- 配置当前消费者同一规则:所有的服务都不检查 -->
<dubbo:consumer check="false" timeout="5000"></dubbo:consumer>
服务提供者也可以设置超时时间
<!-- 4 暴露服务 ref 指向服务的真正实现对象 -->
<dubbo:service interface="com.atguigu.gmail.service.UserService"
ref="userServiceImpl" timeout="1000"></dubbo:service>
超时规则
1.精确优先(方法级优先,接口次之,全局配置再次之)
2.消费者设置优先(如果级别一样,则消费方优先,提供方次之)
案例 :如果我们在提供方配置设置方法级别的超时时间2000ms,服务消费方接口设置超时时间4000ms ,这样的配置依然会报超时错误,因为优先的级别是按照上面的图,先方法级别,再接口级别的生效方式
4、重试次数
失败自动切换,当出现失败,重试其它服务器,但重试会带来更长延迟。可通过 retries="3" 来设置重试次数(不含第一次)一共就是4次。一般配合的是timeout使用
<!-- 调用的服务 -->
<!-- timeout="0" 超时 -->
<!-- retires=“” 重试次数,不包含第一次 -->
<dubbo:reference interface="com.atguigu.gmail.service.UserService"
id="userService" timeout="5000" retries="3">
</dubbo:reference>
这里有一个说明 就是幂等操作和非幂等操作
1.幂等操作(设置重置次数)【查询、修改、删除】 这些操作的结果是相同的
2.非幂等操作(不能设置重置次数)【新增】因为有可能在超时时间内,这一次操作已经发送给数据库,只不过还没有执行完成,重试后可能插入相同的数据很多次
5、版本号
当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。
可以按照以下的步骤进行版本迁移:
0.在低压力时间段,先升级一半提供者为新版本
1.再将所有消费者升级为新版本
2.然后将剩下的一半提供者升级为新版本
代码实现
我们创建两个版本的UserServiceImple 一个是如图
UserServiceImpl.java代码 这个是旧版本代码
public class UserServiceImpl implements UserService {
public List<UserAddress> getUserAddressList(String userId) {
System.out.println("UserServiceImpl...old");
UserAddress address1 = new UserAddress(1,"东长安街89号","1","李老师","13278977","1");
UserAddress address2 = new UserAddress(2,"西长安街89号","1","李老师","13278977","1");
return Arrays.asList(address1,address2);
}
}
UserServiceImpl2.java代码 这个是新版本代码
public class UserServiceImpl2 implements UserService {
public List<UserAddress> getUserAddressList(String userId) {
System.out.println("UserServiceImpl...new");
UserAddress address1 = new UserAddress(1,"东长安街89号","1","李老师","13278977","1");
UserAddress address2 = new UserAddress(2,"西长安街89号","1","李老师","13278977","1");
return Arrays.asList(address1,address2);
}
}
我们在provider.xml文件中进行配置版本 其他的代码不动,只增加了dubbo对外暴露的服务和实例bean
<!-- 4 暴露服务 ref 指向服务的真正实现对象 -->
<dubbo:service interface="com.atguigu.gmail.service.UserService"
ref="userServiceImpl01" version="1.0.0"></dubbo:service>
<bean class="com.atguigu.gmail.service.impl.UserServiceImpl"
id="userServiceImpl01" ></bean>
<dubbo:service interface="com.atguigu.gmail.service.UserService"
ref="userServiceImpl02" version="2.0.0"></dubbo:service>
<bean class="com.atguigu.gmail.service.impl.UserServiceImpl2"
id="userServiceImpl02"></bean>
我们在消费者服务的配置之中增加对应的调用的服务consumer.xml 在<dubbo:reference > 标签中增加了version="1.0.0"
①启动服务提供者主启动类ProviderMainApplication,然后在启动消费者主启动类ConsumerMainApplication
②修改consumer.xml 在<dubbo:reference > 标签中增加了version="2.0.0",然后在启动消费者主启动类ConsumerMainApplication
<!-- 调用的服务 -->
<!-- timeout="0" 超时 -->
<dubbo:reference interface="com.atguigu.gmail.service.UserService"
id="userService" timeout="5000" retries="3" version="1.0.0">
<!-- 可以指定方法名,也可以指定超时时间 -->
<dubbo:method name="getUserAddressList" timeout="1000"></dubbo:method>
</dubbo:reference>
两次操作截图
我们可以看到ProviderMainApplication控制台的两次调用的日志,第一次对应的是旧版本的服务,第二次是新版本的服务,这样就可以控制我们调用服务对于版本的控制了。如果我们在consumer.xml 中配置version="*"调用的版本就是随机的
6、本地存根
远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑,比如:做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 API 中带上 Stub,客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub [1],然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy。
consumer.xml代码 增加一个本地存个属性
<!-- 调用的服务 -->
<!-- timeout="0" 超时 -->
<dubbo:reference interface="com.atguigu.gmail.service.UserService"
id="userService" timeout="5000" retries="3" version="1.0.0"
stub="com.atguigu.gmail.service.impl.UserServiceStub">
创建一个本地存根的实现类UserServiceIStub.java
构造方法传入的远程服务的代理对象,实现接口的方法中可以增加一些验证,缓存或是其他的代码,通过就可以通过代理对象调用远程的服务,否则不调用了。
public class UserServiceStub implements UserService {
private final UserService userService;
/**
* 传入的是userService 远程代理对象
* @param userService
*/
public UserServiceStub(UserService userService) {
super();
this.userService = userService;
}
public List<UserAddress> getUserAddressList(String userId) {
System.out.println("UserServiceStub...");
//在这个验证之前我们可以实现一些需要的业务验证
if(StringUtils.isEmpty(userId)){
//此时代理对象调用远程服务的
return userService.getUserAddressList(userId);
}
return null;
}
}
7Dubbo与SpringBoot 整合的三种方法
1)导入dubbo-starter,在application.properties配置属性,使用@Service【暴露服务】使用@Reference【应用服务】这种方式一定要在SpringBootApplication 上增加@EnableDubbo 开启基于注解的配置
2)导入dubbo-starter,保留dubbo.xml配置文件
将application.properties文件中的配置都注释掉,也就是相当于provider.xml文件放入到resource资源目录下,暴露服务上面@Service注解也可以去掉了
3)使用注解API的方式
将每一个组件创建到容器中 项目结构如图
写一个配置类MyDubboConfig.java 对应的Bean 也就是provider.xml 的配置
@Configuration
public class MyDubboConfig {
/**
* <dubbo:application name="boot-user-service-provider">
* </dubbo:application>
* 对应下面的代码
* @return
*/
@Bean
public ApplicationConfig applicationConfig(){
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("boot-user-service-provider");
return applicationConfig;
}
/**
* <dubbo:registry protocol="zookeeper" address="10.5.96.48:2181">
* </dubbo:registry>
* @return
*/
@Bean
public RegistryConfig registryConfig(){
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setProtocol("zookeeper");
registryConfig.setAddress("10.5.96.48:2181");
return registryConfig;
}
/**
* <!-- 3 指定通信规则 通信协议,通信端口-->
<dubbo:protocol name="dubbo" port="20880"></dubbo:protocol>
* @return
*/
@Bean
public ProtocolConfig protocolConfig(){
ProtocolConfig protocolConfig = new ProtocolConfig();
protocolConfig.setName("dubbo");
protocolConfig.setPort(20882);
return protocolConfig;
}
/**
* <dubbo:service interface="com.atguigu.gmail.service.UserService"
ref="userServiceImpl01" version="1.0.0">
<dubbo:method name="getUserAddressList" timeout="3000"></dubbo:method>
</dubbo:service>
*/
public ServiceConfig<UserService> userServiceConfig(UserService userService){
ServiceConfig<UserService> serviceConfig = new ServiceConfig();
serviceConfig.setInterface(UserService.class);
serviceConfig.setRef(userService);
serviceConfig.setVersion("1.0.0");
//配置每一个method的信息
MethodConfig methodConfig = new MethodConfig();
methodConfig.setName("getUserAddressList");
methodConfig.setTimeout(1000);
//将method 的设置关联到service 配置中
List<MethodConfig> methods = new ArrayList<>();
methods.add(methodConfig);
serviceConfig.setMethods(methods);
return serviceConfig;
}
}
本文地址:https://blog.csdn.net/Be_nurturing/article/details/107316105
上一篇: 国际化资源管理模块重构总结
下一篇: [C#]设计模式-单例模式-创建型模式