难度系统 : ⭐⭐⭐⭐⭐
Dubbo服务导出,调用ServiceBean#export(), 再去调用父类ServiceConfig#export()方法,进行服务真正导出;
主要就是这几个过程, 更简单点 确定服务配置参数 => 启动容器 => 注册到注册中心;
如:
127.0.0.1:8080/com.dubbo.demo.DemoService?group=user&version=1.0&timout=5000&applicationName=demo
dubbo使用的是第四种,来唯一定义一个Service服务;
如果这几处地方同时配置了同一个参数, 优先级由高到低为:
SystemConfig > AppExternalConfiguration > ExternalConfiguration > AbstractConfig > PropertiesConfiguration
即-D方式配置的参数优先级最高,配置中心次之,注解随后,dubbo.properties最后。
因为配置参数同时可以在多个地方配置,所以服务导出的第一步就是确定服务的配置参数;
public synchronized void export() {
//确定配置参数
checkAndUpdateSubConfigs();
//...省略部分代码
// 导出服务
doExport();
}
}
工作:
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(" 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);
}
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());
}
}
}
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();
}
工作:
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);
}
}
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容器中;
可以看出分别获取,按顺序的就可以初步知道优先级了。
系统配置变量 > 配置中心 > 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>();
}
可以得知: 默认情况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文件配置;
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) {
//...
}
}
目的: 获取配置中心的配置;
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);
}
}
}
上面的步骤只是刷新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, 不重复码了。
目的: 如果没有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;
}
目的:获取设置ProtocolConfig;
工作:
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);
}
}
如果没有配置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;
})
);
}
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, 通用性非常强;
确定配置参数仅仅只是服务导出的第一步, 反射技术还是必须要会的技术, 基本框架底层都使用, 任重倒运;