用户登录
用户注册

分享至

Dubbo配置_2

  • 作者: usuussggsh
  • 来源: 51数据库
  • 2021-09-20

配置的官方网址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.51sjk.com/Upload/Articles/1/0/264/264594_2021070800405406001.jpg"
	xmlns:xsi="http://www.51sjk.com/Upload/Articles/1/0/264/264594_20210708004054075.jpg"
	xmlns:dubbo="http://www.51sjk.com/Upload/Articles/1/0/264/264594_2021070800405407501.jpg"
	xmlns:context="http://www.51sjk.com/Upload/Articles/1/0/264/264594_2021070800405407502.jpg"
	xsi:schemaLocation="http://www.51sjk.com/Upload/Articles/1/0/264/264594_2021070800405406001.jpg http://www.51sjk.com/Upload/Articles/1/0/264/264594_2021070800405406001.jpg/spring-beans.xsd
		http://www.51sjk.com/Upload/Articles/1/0/264/264594_2021070800405407502.jpg http://www.51sjk.com/Upload/Articles/1/0/264/264594_2021070800405407502.jpg/spring-context-4.3.xsd
		http://www.51sjk.com/Upload/Articles/1/0/264/264594_2021070800405407501.jpg http://www.51sjk.com/Upload/Articles/1/0/264/264594_2021070800405407501.jpg/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;
		
	}

}

?

软件
前端设计
程序设计
Java相关