Dubbo服务导出
难度系统 : ⭐⭐⭐⭐⭐
Dubbo服务导出,调用ServiceBean#export(), 再去调用父类ServiceConfig#export()方法,进行服务真正导出;
Dubbo服务导出大体流程
- Dubbo的每个Service注解都对应一个ServiceBean对象,每个ServiceBean对象都实现了Spring的ApplicationListener接口,当Spring项目启动结束后,会触发一个上下文刷新事件ContextRefreshEvent事件, 触发的方法是onApplicationEvent方法, ServiceBean的onApplicationEvent方法中,会调用ServiceBean#export(), 再去调用父类ServiceConfig#export()方法进行服务导出
- 会确定每个ServiceBean的配置参数,像timeout, protocol等, 这些参数的配置可以在以下的地方进行配置;
2.1 JVM环境运行参数, 通过-D的方式来指定参数
2.2 配置中心可以配置 项目的全局配置和应用配置, 相当于一个分布式共享的Dubbo.properties文件;
2.3 @Service注解可以指定参数;
2.4 项目中, 指定的dubbo.properties配置文件;
这么多个地方可以指定配置参数, 在服务导出时,就需要确定每个Service使用的是哪些配置参数,即确定优先级最高的参数; - 加载确定注册中心信息;
- 根据配置的Protocol协议启动容器, Dubbo协议对应的Netty, http对应的是tomcat/jetty, 并在接收请求过程中,根据我们的配置接收请求, 如超时事件, 最大连接数等;
- 容器启动完后,每个ServiceBean的服务配置会注册到注册中心,同时会注册监听服务配置,监听配置的变更;
主要就是这几个过程, 更简单点 确定服务配置参数 => 启动容器 => 注册到注册中心;
服务概念
- 传统三层调用中,Service接口就是服务的定义,而ServiceImpl就是服务的具体是实现;dubbo也是如此;
- Service接口 + 分组group + 版本号version 更详细的定义了一个服务;
- ip:port/service接口:通过IP端口号远程访问一个服务;
- ip:port/service接口 ?group =xxx & version=xxx & timeout=xxx & … : 通过IP端口指定远程服务器, 通过service接口 + 接口配置参数更详细的定义了一个服务,确定服务的唯一性;
如:
127.0.0.1:8080/com.dubbo.demo.DemoService?group=user&version=1.0&timout=5000&applicationName=demo
dubbo使用的是第四种,来唯一定义一个Service服务;
服务导出代码流程总结
- 加载确定服务的配置参数;
- 加载注册中心URL信息;
- 构造服务最终的URL;
- 根据协议配置Protolcol启动不同的容器,用来接收请求;
- 服务URL注册到注册中心中;
- 监听服务配置信息,配置发生变更,则重新进行服务导出;
加载确定服务的配置参数
- 每个@Service对应一个ServiceBean服务配置实例, 而服务启动过程中,@DubboComponentScan注解执行完毕, 会把每个@Service转换一个个得ServiceBean实例, 并把@Service注解中的配置信息赋值给了ServiceBean实例,包括一些普通值timeout, 还有一些Dubbo配置, 如protocolConfig等;
- 在Dubbo中,除开可以在@Service注解中给服务配置参数,还有很多地方也可以给服务配置参数
- resouce资源文件dubbo.properties: Dubbo会去扫描这些配置文件, 加载为PropertiesConfiguration;
- 配置中心:一个分布式的properties文件, 包括两种,一种是全局配置,另一个种是应用配置;在Dubbo的源码中AppExternalConfiguration表示应用配置,ExternalConfiguration表示全局配置。
- @Service注解: 对应的AbstractConfig;
- JVM环境参数: 通过-D执行配置, 对应的类是SystemConfiguration;
-
如果这几处地方同时配置了同一个参数, 优先级由高到低为:
SystemConfig > AppExternalConfiguration > ExternalConfiguration > AbstractConfig > PropertiesConfiguration
即-D方式配置的参数优先级最高,配置中心次之,注解随后,dubbo.properties最后。 -
因为配置参数同时可以在多个地方配置,所以服务导出的第一步就是确定服务的配置参数;
ServiceConfig#export()
public synchronized void export() {
//确定配置参数
checkAndUpdateSubConfigs();
//...省略部分代码
// 导出服务
doExport();
}
}
ServiceConfig#checkAndUpdateSubConfigs()
工作:
- completeCompoundConfigs补全配置参数
- 从配置中心获取应用配置和全局配置
- 获取ProviderConfig对象;
- 获取Protocol协议对象,默认为Dubbo协议;
- 获取ApplicationConfig对象;
- 获取Registry服务配置;
- 更新ServiceConfig 参数为最高优先级的配置;
- 检查当前服务是不是一个泛化服务
- 检查Stub和Local
- 检查Mock
public void checkAndUpdateSubConfigs() {
completeCompoundConfigs();
// Config Center should always being started first.
// 从配置中心获取配置,包括应用配置和全局配置
// 把获取到的配置放入到Environment中的externalConfigurationMap和appExternalConfigurationMap中
// 并刷新所有的Config属性
startConfigCenter();
// 如果没有ProviderConfig对象,则创建一个
checkDefault();
// 如果没有单独的配置protocols,那么就从provider获取配置的协议,添加到的ServiceConfig中去
// 假如程序员在配置文件中配了一个dubbo协议,配置中心的全局配置或应用配置中也配置了一个协议,那么就会被添加到ServiceConfig中
checkProtocol();
checkApplication();
// if protocol is not injvm checkRegistry
// 如果protocol不是只有injvm协议,表示服务调用不是只在本机jvm里面调用,那就需要用到注册中心
// 如果protocol是injvm,表示本地调用
if (!isOnlyInJvm()) {
checkRegistry();
}
// 刷新ServiceConfig
this.refresh();
// 如果配了metadataReportConfig,那么就刷新配置
checkMetadataReport();
if (StringUtils.isEmpty(interfaceName)) {
throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
}
// 当前服务对应的实现类是一个GenericService,表示没有特定的接口
if (ref instanceof GenericService) {
interfaceClass = GenericService.class;
if (StringUtils.isEmpty(generic)) {
generic = Boolean.TRUE.toString();
}
} else {
// 加载接口
try {
interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
.getContextClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
// 刷新MethodConfig,并判断MethodConfig中对应的方法在接口中是否存在
checkInterfaceAndMethods(interfaceClass, methods);
// 实现类是不是该接口类型
checkRef();
generic = Boolean.FALSE.toString();
}
// local和stub一样,不建议使用了
if (local != null) {
// 如果本地存根为true,则存根类为interfaceName + "Local"
if (Boolean.TRUE.toString().equals(local)) {
local = interfaceName + "Local";
}
// 加载本地存根类
Class<?> localClass;
try {
localClass = ClassUtils.forNameWithThreadContextClassLoader(local);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
if (!interfaceClass.isAssignableFrom(localClass)) {
throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName);
}
}
// 本地存根
if (stub != null) {
// 如果本地存根为true,则存根类为interfaceName + "Stub"
if (Boolean.TRUE.toString().equals(stub)) {
stub = interfaceName + "Stub";
}
Class<?> stubClass;
try {
stubClass = ClassUtils.forNameWithThreadContextClassLoader(stub);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
if (!interfaceClass.isAssignableFrom(stubClass)) {
throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName);
}
}
// 检查local和stub
checkStubAndLocal(interfaceClass);
// 检查mock
checkMock(interfaceClass);
}
ServiceConfig#completeCompoundConfigs()’
- 配置了provider, 而没有配置application, module, registeries, monitor ,protocols ,configCenter , 则从provider种获取这些配置;
- 配置了module,而没有配置registries, configCenter, 则从module中获取这些配置;
- 配置了application, 而没有配置registries , monitor ,则从application中获取这些配置;
private void completeCompoundConfigs() {
// 如果配置了provider,那么则从provider中获取信息赋值其他属性,在这些属性为空的情况下
if (provider != null) {
if (application == null) {
setApplication(provider.getApplication());
}
if (module == null) {
setModule(provider.getModule());
}
if (registries == null) {
setRegistries(provider.getRegistries());
}
if (monitor == null) {
setMonitor(provider.getMonitor());
}
if (protocols == null) {
setProtocols(provider.getProtocols());
}
if (configCenter == null) {
setConfigCenter(provider.getConfigCenter());
}
}
// 如果配置了module,那么则从module中获取信息赋值其他属性,在这些属性为空的情况下
if (module != null) {
if (registries == null) {
setRegistries(module.getRegistries());
}
if (monitor == null) {
setMonitor(module.getMonitor());
}
}
// 如果配置了application,那么则从application中获取信息赋值其他属性,在这些属性为空的情况下
if (application != null) {
if (registries == null) {
setRegistries(application.getRegistries());
}
if (monitor == null) {
setMonitor(application.getMonitor());
}
}
}
ServiceConfig#startConfigCenter()
- 配置configCenter, 从其他位置获取配置中心的相关属性信息,比如配置中心地址
- 更新属性后, 从配置中获取全局配置,应用配置;
- 拿到配置后, 刷新所有XXXconfig的属性;
void startConfigCenter() {
if (configCenter == null) {
ConfigManager.getInstance().getConfigCenter().ifPresent(cc -> this.configCenter = cc);
}
// 如果配置了ConfigCenter
if (this.configCenter != null) {
// TODO there may have duplicate refresh
this.configCenter.refresh();
// 属性更新后,从远程配置中心获取数据(应用配置,全局配置)
prepareEnvironment();
}
// 从配置中心取到配置数据后,刷新所有的XxConfig中的属性
ConfigManager.getInstance().refreshAll();
}
ServiceConfig#refresh
工作:
- 获取所有相关的dubbo配置;
- 创建一个Configuration对象,代表AbstractConfig;
- isConfigCenterFirst的值默认为true,所以优先级的顺序为:系统变量->配置中心应用配置->配置中心全局配置->注解或xml中定义->dubbo.properties文件;
- 使用反射技术赋最高优先级别配置的值;
public void refresh() {
try {
CompositeConfiguration compositeConfiguration = Environment.getInstance().getConfiguration(getPrefix(), getId());
// 表示XxConfig对象本身- AbstractConfig
Configuration config = new ConfigConfigurationAdapter(this);
if (Environment.getInstance().isConfigCenterFirst()) {
// The sequence would be: SystemConfiguration -> AppExternalConfiguration -> ExternalConfiguration -> AbstractConfig -> PropertiesConfiguration
compositeConfiguration.addConfiguration(4, config);
} else {
// The sequence would be: SystemConfiguration -> AbstractConfig -> AppExternalConfiguration -> ExternalConfiguration -> PropertiesConfiguration
compositeConfiguration.addConfiguration(2, config);
}
// loop methods, get override value and set the new value back to method
//
Method[] methods = getClass().getMethods();
for (Method method : methods) {
// 是不是setXX()方法
if (MethodUtils.isSetter(method)) {
// 获取xx配置项的value
String value = StringUtils.trim(compositeConfiguration.getString(extractPropertyName(getClass(), method)));
// isTypeMatch() is called to avoid duplicate and incorrect update, for example, we have two 'setGeneric' methods in ReferenceConfig.
if (StringUtils.isNotEmpty(value) && ClassUtils.isTypeMatch(method.getParameterTypes()[0], value)) {
method.invoke(this, ClassUtils.convertPrimitive(method.getParameterTypes()[0], value));
}
// 是不是setParameters()方法
} else if (isParametersSetter(method)) {
// 获取parameter配置项的value
String value = StringUtils.trim(compositeConfiguration.getString(extractPropertyName(getClass(), method)));
if (StringUtils.isNotEmpty(value)) {
Map<String, String> map = invokeGetParameters(getClass(), this);
map = map == null ? new HashMap<>() : map;
map.putAll(convert(StringUtils.parseParameters(value), ""));
invokeSetParameters(getClass(), this, map);
}
}
}
} catch (Exception e) {
logger.error("Failed to override ", e);
}
}
配置中心配置确定优先级
Environment.getInstance().getConfiguration(getPrefix(), getId())
getInstance():单例饿汉式;
public class Environment {
//存放各种配置;
private Map<String, PropertiesConfiguration> propertiesConfigs = new ConcurrentHashMap<>();
private Map<String, SystemConfiguration> systemConfigs = new ConcurrentHashMap<>();
private Map<String, EnvironmentConfiguration> environmentConfigs = new ConcurrentHashMap<>();
private Map<String, InmemoryConfiguration> externalConfigs = new ConcurrentHashMap<>();
private Map<String, InmemoryConfiguration> appExternalConfigs = new ConcurrentHashMap<>();
private static final Environment INSTANCE = new Environment();
public static Environment getInstance() {
return INSTANCE;
}
}
getConfiguration:获取配置,放入CompositeConfiguration 内部的List容器中;
- JVM环境变量
- 操作系统环境变量(我没接触过)
- 配置中心APP配置
- 配置中心Global全局配置
- dubbo.properties中的配置
- 返回compositeConfiguration实例;
可以看出分别获取,按顺序的就可以初步知道优先级了。
系统配置变量 > 配置中心 > dubbo文件配置;
public CompositeConfiguration getConfiguration(String prefix, String id) {
CompositeConfiguration compositeConfiguration = new CompositeConfiguration();
// Config center has the highest priority
// JVM环境变量
compositeConfiguration.addConfiguration(this.getSystemConfig(prefix, id));
// 操作系统环境变量
compositeConfiguration.addConfiguration(this.getEnvironmentConfig(prefix, id));
// 配置中心APP配置
compositeConfiguration.addConfiguration(this.getAppExternalConfig(prefix, id));
// 配置中心Global配置
compositeConfiguration.addConfiguration(this.getExternalConfig(prefix, id));
// dubbo.properties中的配置
compositeConfiguration.addConfiguration(this.getPropertiesConfig(prefix, id));
return compositeConfiguration;
}
CompositeConfiguration类: 内部有一个List集合,存放配置;
public class CompositeConfiguration implements Configuration {
/**
* List holding all the configuration
*/
private List<Configuration> configList = new LinkedList<Configuration>();
}
Environment.getInstance().isConfigCenterFirst()
可以得知: 默认情况configCenterFirst的值为true;
public class Environment {
private static final Environment INSTANCE = new Environment();
private boolean configCenterFirst = true;
public boolean isConfigCenterFirst() {
return configCenterFirst;
}
}
因此,下面代码中, 往集合的第4个位置, 插入代表AbstractConfig的配置;
public void refresh() {
try {
CompositeConfiguration compositeConfiguration = Environment.getInstance().getConfiguration(getPrefix(), getId());
// 表示XxConfig对象本身- AbstractConfig
Configuration config = new ConfigConfigurationAdapter(this);
if (Environment.getInstance().isConfigCenterFirst()) {
compositeConfiguration.addConfiguration(4, config);
} else {
compositeConfiguration.addConfiguration(2, config);
}
//...
}
最终配置的优先级为: 系统配置变量 > 配置中心 > @Service注解配置 > dubbo文件配置;
配置中心配置赋最高优先级别的值
- 获取ServiceConfig配置类的所有方法
- 遍历Method
- 判断是否为setter方法;
- 如果是setter方法, 则使用compositeConfiguration.getString(extractPropertyName(getClass(), method)获取属性的值
4.1 遍历compositeConfiguration内部的已经排好序的Configuration集合List
4.2 Configuration判断是否包含了当前key, 包含就说明找到优先级最高的配置,返回; - 通过反射赋值;
- 如果不是setter方法, 是setParameters方法;
- 获取parameter配置项的value;
- 通过反射调用getParameters方法获取parameter值;
- 合并parameter的值, 通过反射调用setParameter方法赋值;
public void refresh() {
try {
//...省略确定优先级别的代码
Method[] methods = getClass().getMethods();
for (Method method : methods) {
// 是不是setXX()方法
if (MethodUtils.isSetter(method)) {
// 获取xx配置项的value
String value = StringUtils.trim(compositeConfiguration.getString(extractPropertyName(getClass(), method)));
// isTypeMatch() is called to avoid duplicate and incorrect update, for example, we have two 'setGeneric' methods in ReferenceConfig.
if (StringUtils.isNotEmpty(value) && ClassUtils.isTypeMatch(method.getParameterTypes()[0], value)) {
method.invoke(this, ClassUtils.convertPrimitive(method.getParameterTypes()[0], value));
}
// 是不是setParameters()方法
} else if (isParametersSetter(method)) {
// 获取parameter配置项的value
String value = StringUtils.trim(compositeConfiguration.getString(extractPropertyName(getClass(), method)));
if (StringUtils.isNotEmpty(value)) {
Map<String, String> map = invokeGetParameters(getClass(), this);
map = map == null ? new HashMap<>() : map;
map.putAll(convert(StringUtils.parseParameters(value), ""));
invokeSetParameters(getClass(), this, map);
}
}
}
} catch (Exception e) {
//...
}
}
prepareEnvironment()
目的: 获取配置中心的配置;
- 获取动态配置中心;
- 获取全局配置的内容configContent ;
- 获取管理组名;
- 如果存在管理组,则有App应用配置, 获取应用配置的内容appConfigContent ;
- 设置configCenterFirst属性值为true;
- 解析全局配置内容,并赋值给Environment#externalConfigurationMap;
- 解析应用配置内容, 并赋值给Environment#appExternalConfigurationMap
private void prepareEnvironment() {
if (configCenter.isValid()) {
if (!configCenter.checkOrUpdateInited()) {
return;
}
// 动态配置中心,管理台上的配置中心
DynamicConfiguration dynamicConfiguration = getDynamicConfiguration(configCenter.toUrl());
// 如果是zookeeper,获取的就是/dubbo/config/dubbo/dubbo.properties节点中的内容
String configContent = dynamicConfiguration.getProperties(configCenter.getConfigFile(), configCenter.getGroup());
String appGroup = application != null ? application.getName() : null;
String appConfigContent = null;
if (StringUtils.isNotEmpty(appGroup)) {
// 获取的就是/dubbo/config/dubbo-demo-consumer-application/dubbo.properties节点中的内容
// 这里有bug
appConfigContent = dynamicConfiguration.getProperties
(StringUtils.isNotEmpty(configCenter.getAppConfigFile()) ? configCenter.getAppConfigFile() : configCenter.getConfigFile(),
appGroup
);
}
try {
Environment.getInstance().setConfigCenterFirst(configCenter.isHighestPriority());
Environment.getInstance().updateExternalConfigurationMap(parseProperties(configContent));
Environment.getInstance().updateAppExternalConfigurationMap(parseProperties(appConfigContent));
} catch (IOException e) {
throw new IllegalStateException("Failed to parse configurations from Config Center.", e);
}
}
}
ConfigManager.getInstance().refreshAll()
上面的步骤只是刷新ConfigCenterConfig的最新值;而其他配置类例如ApplicationConfig, ProtocolConfig等的值不是最高优先级别的值, 因此这些配置类也需要刷新, 赋最高优先级别的值;
public void refreshAll() {
// refresh all configs here,
getApplication().ifPresent(ApplicationConfig::refresh);
getMonitor().ifPresent(MonitorConfig::refresh);
getModule().ifPresent(ModuleConfig::refresh);
getProtocols().values().forEach(ProtocolConfig::refresh);
getRegistries().values().forEach(RegistryConfig::refresh);
getProviders().values().forEach(ProviderConfig::refresh);
getConsumers().values().forEach(ConsumerConfig::refresh);
}
代码写得非常漂亮, 使用反射,因此通用性很高;
过程类似ConfigCenterConfig, 不重复码了。
ServiceConfig#checkDefault()
目的: 如果没有ProviderConfig对象,则创建一个
private void checkDefault() {
createProviderIfAbsent();
}
private void createProviderIfAbsent() {
if (provider != null) {
return;
}
setProvider(
ConfigManager.getInstance()
.getDefaultProvider()
.orElseGet(() -> {
//创建ProviderConfig实例,并赋最高优先级别的值;
ProviderConfig providerConfig = new ProviderConfig();
providerConfig.refresh();
return providerConfig;
})
);
}
//给配置管理器设置Provider;
public void setProvider(ProviderConfig provider) {
ConfigManager.getInstance().addProvider(provider);
this.provider = provider;
}
ServiceConfig#checkProtocol
目的:获取设置ProtocolConfig;
工作:
- 如果没有单独的配置protocols,那么就从provider获取配置的协议,添加到的ServiceConfig中去
- 假如程序员在配置文件中配了一个dubbo协议,配置中心的全局配置或应用配置中也配置了一个协议,那么就会被添加到ServiceConfig中
2.1 获取全局配置的protocol, 根据前缀"dubbo.protocols." 从externalConfigurationMap中获取;
2.2 获取应用配置的protocol, 根据前缀"dubbo.protocols." 从appExternalConfigurationMap中获取;
2.3 拼接配置;
2.4 如果配置中心没有配置,则使用默认的Dubbo协议配置, 创建一个默认的ProtocolConfig 赋值给ConfigManager管理;
2.5 如果配置中心有配置,则分别创建每个配置创建一个ProtocolConfig, 然后一起交给ConfigManager管理;
private void checkProtocol() {
//如果没有单独的配置protocols,那么就从provider获取配置的协议,添加到的ServiceConfig中去
if (CollectionUtils.isEmpty(protocols) && provider != null) {
setProtocols(provider.getProtocols());
}
convertProtocolIdsToProtocols();
}
private void convertProtocolIdsToProtocols() {
if (StringUtils.isEmpty(protocolIds) && CollectionUtils.isEmpty(protocols)) {
List<String> configedProtocols = new ArrayList<>();
// 从配置中心的全局配置获取dubbo.protocols.的配置项值
configedProtocols.addAll(getSubProperties(Environment.getInstance()
.getExternalConfigurationMap(), PROTOCOLS_SUFFIX));
// 从配置中心的应用配置获取dubbo.protocols.的配置项值
configedProtocols.addAll(getSubProperties(Environment.getInstance()
.getAppExternalConfigurationMap(), PROTOCOLS_SUFFIX));
// 用,号join所有的protocol
protocolIds = String.join(",", configedProtocols);
}
if (StringUtils.isEmpty(protocolIds)) {
// 如果配置中心没有配置协议,就取默认的协议
if (CollectionUtils.isEmpty(protocols)) {
setProtocols(
ConfigManager.getInstance().getDefaultProtocols()
.filter(CollectionUtils::isNotEmpty)
.orElseGet(() -> {
ProtocolConfig protocolConfig = new ProtocolConfig();
protocolConfig.refresh();
return new ArrayList<>(Arrays.asList(protocolConfig));
})
);
}
} else {
// 如果配置了
String[] arr = COMMA_SPLIT_PATTERN.split(protocolIds);
List<ProtocolConfig> tmpProtocols = CollectionUtils.isNotEmpty(protocols) ? protocols : new ArrayList<>();
// 把从配置中心配置的协议添加到服务的协议列表中去
Arrays.stream(arr).forEach(id -> {
if (tmpProtocols.stream().noneMatch(prot -> prot.getId().equals(id))) {
tmpProtocols.add(ConfigManager.getInstance().getProtocol(id).orElseGet(() -> {
ProtocolConfig protocolConfig = new ProtocolConfig();
protocolConfig.setId(id);
protocolConfig.refresh();
return protocolConfig;
}));
}
});
if (tmpProtocols.size() > arr.length) {
throw new IllegalStateException("Too much protocols found, the protocols comply to this service are :" + protocolIds + " but got " + protocols
.size() + " registries!");
}
setProtocols(tmpProtocols);
}
}
checkApplication()
如果没有配置application,则创建一个ApplicationConfig实例,赋值给ConfigManager;
protected void checkApplication() {
// for backward compatibility
createApplicationIfAbsent();
//...省略不重要代码
}
private void createApplicationIfAbsent() {
if (this.application != null) {
return;
}
ConfigManager configManager = ConfigManager.getInstance();
setApplication(
configManager
.getApplication()
.orElseGet(() -> {
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.refresh();
return applicationConfig;
})
);
}
ServiceConfig#refresh()
- this.refresh()逻辑和ConfigCenterConfig的刷新代码逻辑一样的;
- ServiceConfig对象的属性可能是有值的,也可能是没有值的,这时需要从其他位置获取属性值,来进行属性的覆盖
- ServiceConfig本身有很多配置, 通过刷新获取最高优先级的配置值;例如timeout, 如果注解上没有配置这个值,就会从其他地方获取配置;
- 覆盖的优先级,从大到小为系统变量->配置中心应用配置->配置中心全局配置->注解或xml中定义->dubbo.properties文件
- 将当前ServiceConfig上的set方法所对应的属性更新为优先级最高的值
public void refresh() {
try {
//TODO : 都没启动configCenter,配置中心的配置是怎么拿到的????
CompositeConfiguration compositeConfiguration = Environment.getInstance().getConfiguration(getPrefix(), getId());
// 表示XxConfig对象本身- AbstractConfig
Configuration config = new ConfigConfigurationAdapter(this);
if (Environment.getInstance().isConfigCenterFirst()) {
// The sequence would be: SystemConfiguration -> AppExternalConfiguration -> ExternalConfiguration -> AbstractConfig -> PropertiesConfiguration
compositeConfiguration.addConfiguration(4, config);
} else {
// The sequence would be: SystemConfiguration -> AbstractConfig -> AppExternalConfiguration -> ExternalConfiguration -> PropertiesConfiguration
compositeConfiguration.addConfiguration(2, config);
}
// loop methods, get override value and set the new value back to method
//
Method[] methods = getClass().getMethods();
for (Method method : methods) {
// 是不是setXX()方法
if (MethodUtils.isSetter(method)) {
// 获取xx配置项的value
String value = StringUtils.trim(compositeConfiguration.getString(extractPropertyName(getClass(), method)));
// isTypeMatch() is called to avoid duplicate and incorrect update, for example, we have two 'setGeneric' methods in ReferenceConfig.
if (StringUtils.isNotEmpty(value) && ClassUtils.isTypeMatch(method.getParameterTypes()[0], value)) {
method.invoke(this, ClassUtils.convertPrimitive(method.getParameterTypes()[0], value));
}
// 是不是setParameters()方法
} else if (isParametersSetter(method)) {
// 获取parameter配置项的value
String value = StringUtils.trim(compositeConfiguration.getString(extractPropertyName(getClass(), method)));
if (StringUtils.isNotEmpty(value)) {
Map<String, String> map = invokeGetParameters(getClass(), this);
map = map == null ? new HashMap<>() : map;
map.putAll(convert(StringUtils.parseParameters(value), ""));
invokeSetParameters(getClass(), this, map);
}
}
}
} catch (Exception e) {
logger.error("Failed to override ", e);
}
}
到这里,主要的服务导出确定服务配置参数过程就完了。代码写得非常nice, 通用性非常强;
总结
确定配置参数仅仅只是服务导出的第一步, 反射技术还是必须要会的技术, 基本框架底层都使用, 任重倒运;