dubbo-源码阅读之服务发布
原理
dubbo根据spring 2.0的schma实现 解析xml并初始化相关bean 初始化dubbo:service为ServiceBean实例 通过spring的生命周期相应回调实现服务发布
ServiceBean源码
import com.alibaba.dubbo.config.*;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.support.AbstractApplicationContext;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* InitializingBean
* 1.初始化的时候会调用afterPropertiesSet方法
* 2.优先级高于init-method
* 3.如果afterPropertiesSet出现异常 则不调用init-method
* DisposableBean
* 1.当调用context.close的时候会执行destroy
* ApplicationContextAware
* 1.初始化对象会传入spring上下文容器
* ApplicationListener事件
* 1.ContextRefreshedEvent
* ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在 ConfigurableApplicationContext接口中使用 refresh() 方法来发生。
* 此处的初始化是指:所有的Bean被成功装载,后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用
* 2.ContextStartedEvent
* 当使用 ConfigurableApplicationContext (ApplicationContext子接口)接口中的 start() 方法启动 ApplicationContext 时,该事件被发布。
* 你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的应用程序
* 3.ContextStoppedEvent
* 当使用 ConfigurableApplicationContext 接口中的 stop() 停止 ApplicationContext 时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作
* 4.ContextClosedEvent
* 当使用 ConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启
* 5.RequestHandledEvent
* 这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。只能应用于使用DispatcherServlet的Web应用。
* 在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件
* @param <T>
*/
class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware {
/**
* ApplicationContextAware接口实现方法
* @param applicationContext
*/
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
SpringExtensionFactory.addApplicationContext(applicationContext);
if (applicationContext != null) {
SPRING_CONTEXT = applicationContext;
try {
Method method = applicationContext.getClass().getMethod("addApplicationListener", ApplicationListener.class);
method.invoke(applicationContext, this);
this.supportedApplicationListener = true;
} catch (Throwable var5) {
if (applicationContext instanceof AbstractApplicationContext) {
try {
Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", ApplicationListener.class);
if (!method.isAccessible()) {
method.setAccessible(true);
}
method.invoke(applicationContext, this);
this.supportedApplicationListener = true;
} catch (Throwable var4) {
;
}
}
}
}
}
/**
* BeanNameAware 接口实现方法
* @param name
*/
public void setBeanName(String name) {
this.beanName = name;
}
/**
* ApplicationListener实现方法
* ContextRefreshedEvent bean被装载则会调用
* @param event
*/
public void onApplicationEvent(ContextRefreshedEvent event) {
if (this.isDelay() && !this.isExported() && !this.isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + this.getInterface());
}
this.export();
}
}
/**
* InitializingBean
* 实现方法
* @throws Exception
*/
public void afterPropertiesSet() throws Exception {
Map providerConfigMap;
/**
* step1
* dubbo:servie未指定provider
* <dubbo:provider id="test1" delay="-1" retries="0" />
* <dubbo:service provider="test1" interface="com.biz.soa.service.seckill.frontend.SoaSeckillFrontService" ref="soaSeckillFrontServiceImpl"/>
*/
if (this.getProvider() == null) {
/**
* step2
* BeanFactoryUtils.beansOfTypeIncludingAncestors为获取指定类型以及实现类和子类的集合 key为name
*/
providerConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ProviderConfig.class, false, false);
/**
* 这里面代码逻辑是混乱的 主要看下面分支吧
*/
if (providerConfigMap != null && providerConfigMap.size() > 0) {
Map<String, ProtocolConfig> protocolConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ProtocolConfig.class, false, false);
Iterator i$;
ProviderConfig config;
/**
*/
if ((protocolConfigMap == null || protocolConfigMap.size() == 0) && protocolConfigMap.size() > 1) {
List<ProviderConfig> providerConfigs = new ArrayList();
i$ = protocolConfigMap.values().iterator();
while(i$.hasNext()) {
config = (ProviderConfig)i$.next();
if (config.isDefault() != null && config.isDefault()) {
providerConfigs.add(config);
}
}
if (!providerConfigs.isEmpty()) {
this.setProviders(providerConfigs);
}
} else {
ProviderConfig providerConfig = null;
i$ = protocolConfigMap.values().iterator();
label318:
/**
* step4
* 这里面需要注意 要么default为true的放到第一个 要么 非default设置为false 没有缺省值 会报Duplicate provider configs
* <dubbo:provider id="test1" delay="-1" retries="0" />
* <dubbo:provider id="test2" default="true" delay="-1" retries="0" />
*/
while(true) {
do {
if (!i$.hasNext()) {
if (providerConfig != null) {
this.setProvider(providerConfig);
}
break label318;
}
config = (ProviderConfig)i$.next();
//以上面数据为列 默认null 结束循环 whlie(true) 第二次进来providerConfig不为空 就会报duplicate异常
} while(config.isDefault() != null && !config.isDefault());
if (providerConfig != null) {
throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config);
}
providerConfig = config;
}
}
}
}
Iterator i$;
/**
* 跟上面逻辑一样 只是是读取application标签
* <dubbo:application name="soa-promotion-provider"/>
*/
if (this.getApplication() == null && (this.getProvider() == null || this.getProvider().getApplication() == null)) {
protocolConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ApplicationConfig.class, false, false);
if (protocolConfigMap != null && protocolConfigMap.size() > 0) {
ApplicationConfig applicationConfig = null;
i$ = protocolConfigMap.values().iterator();
label291:
while(true) {
ApplicationConfig config;
do {
if (!i$.hasNext()) {
if (applicationConfig != null) {
this.setApplication(applicationConfig);
}
break label291;
}
config = (ApplicationConfig)i$.next();
} while(config.isDefault() != null && !config.isDefault());
if (applicationConfig != null) {
throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config);
}
applicationConfig = config;
}
}
}
/**
* 跟上面一样 读取moudule标签
* <dubbo:module name="soa-promotion-provider" version="1.0" owner="liqianng" organization="信息部"></dubbo:module>
*/
if (this.getModule() == null && (this.getProvider() == null || this.getProvider().getModule() == null)) {
protocolConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ModuleConfig.class, false, false);
if (protocolConfigMap != null && protocolConfigMap.size() > 0) {
ModuleConfig moduleConfig = null;
i$ = protocolConfigMap.values().iterator();
label270:
while(true) {
ModuleConfig config;
do {
if (!i$.hasNext()) {
if (moduleConfig != null) {
this.setModule(moduleConfig);
}
break label270;
}
config = (ModuleConfig)i$.next();
} while(config.isDefault() != null && !config.isDefault());
if (moduleConfig != null) {
throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config);
}
moduleConfig = config;
}
}
}
ArrayList protocolConfigs;
/**
* 同上
* <dubbo:registry address="${zookeeper.url}" file=".dubbo/promotion-provider.cache" check="false" />
*/
if ((this.getRegistries() == null || this.getRegistries().isEmpty()) && (this.getProvider() == null || this.getProvider().getRegistries() == null || this.getProvider().getRegistries().isEmpty()) && (this.getApplication() == null || this.getApplication().getRegistries() == null || this.getApplication().getRegistries().isEmpty())) {
protocolConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, RegistryConfig.class, false, false);
if (protocolConfigMap != null && protocolConfigMap.size() > 0) {
protocolConfigs = new ArrayList();
i$ = protocolConfigMap.values().iterator();
label240:
while(true) {
RegistryConfig config;
do {
if (!i$.hasNext()) {
if (protocolConfigs != null && !protocolConfigs.isEmpty()) {
super.setRegistries(protocolConfigs);
}
break label240;
}
config = (RegistryConfig)i$.next();
} while(config.isDefault() != null && !config.isDefault());
protocolConfigs.add(config);
}
}
}
/**
* //表示从注册中心发现监控地址
* <dubbo:monitor protocol="registry"></dubbo:monitor>
*/
if (this.getMonitor() == null && (this.getProvider() == null || this.getProvider().getMonitor() == null) && (this.getApplication() == null || this.getApplication().getMonitor() == null)) {
protocolConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, MonitorConfig.class, false, false);
if (protocolConfigMap != null && protocolConfigMap.size() > 0) {
MonitorConfig monitorConfig = null;
i$ = protocolConfigMap.values().iterator();
label215:
while(true) {
MonitorConfig config;
do {
if (!i$.hasNext()) {
if (monitorConfig != null) {
this.setMonitor(monitorConfig);
}
break label215;
}
config = (MonitorConfig)i$.next();
} while(config.isDefault() != null && !config.isDefault());
if (monitorConfig != null) {
throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config);
}
monitorConfig = config;
}
}
}
/**
* 获取配置的协议信息
* <dubbo:protocol register="false" name="dubbo" port="23888" threadpool="fixed" threads="500" dispatcher="message"/>
*
*/
if ((this.getProtocols() == null || this.getProtocols().isEmpty()) && (this.getProvider() == null || this.getProvider().getProtocols() == null || this.getProvider().getProtocols().isEmpty())) {
protocolConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ProtocolConfig.class, false, false);
if (protocolConfigMap != null && protocolConfigMap.size() > 0) {
protocolConfigs = new ArrayList();
i$ = protocolConfigMap.values().iterator();
label190:
while(true) {
ProtocolConfig config;
do {
if (!i$.hasNext()) {
if (protocolConfigs != null && !protocolConfigs.isEmpty()) {
super.setProtocols(protocolConfigs);
}
break label190;
}
config = (ProtocolConfig)i$.next();
} while(config.isDefault() != null && !config.isDefault());
protocolConfigs.add(config);
}
}
}
if ((this.getPath() == null || this.getPath().length() == 0) && this.beanName != null && this.beanName.length() > 0 && this.getInterface() != null && this.getInterface().length() > 0 && this.beanName.startsWith(this.getInterface())) {
this.setPath(this.beanName);
}
/**
* 是否延迟注册服务 默认为0 以毫秒为单位
*/
if (!this.isDelay()) {
this.export();
}
}
/**
* 是否延迟加载
* @return
*/
private boolean isDelay() {
//从当前service标签获取
Integer delay = this.getDelay();
ProviderConfig provider = this.getProvider();
//如果没有设置则从provider标签获取
if (delay == null && provider != null) {
delay = provider.getDelay();
}
return this.supportedApplicationListener && (delay == null || delay == -1);
}
/**
* DisposableBean实现方法
* @throws Exception
*/
public void destroy() throws Exception {
}
}
真正服务发布的方法 以下方法 该方法为继承父类ServiceConfig的方法
if (!this.isDelay()) {
this.export();
}
ServiceConfig
L export
调用链条:ServiceBean#afterPropertiesSet#export
public synchronized void export() {
if (this.provider != null) {
//<dubbo:service> 获取export配置 是否暴露服务
if (this.export == null) {
//从<dubbo:provider> 获取export配置 是否暴露
this.export = this.provider.getExport();
}
//同上
if (this.delay == null) {
this.delay = this.provider.getDelay();
}
}
//如果标签没有配置或者export为true 则开始暴露服务
if (this.export == null || this.export) {
//如果delay不等于空 或者delay大于0表示延迟加载 延迟加载使用spring 的异步事件实现
if (this.delay != null && this.delay > 0) {
delayExportExecutor.schedule(new Runnable() {
public void run() {
//ServiceConfig.this为内部类对象访问外部类对象的实例
ServiceConfig.this.doExport();
}
}, (long)this.delay, TimeUnit.MILLISECONDS);
} else {
//直接发布
this.doExport();
}
}
}
L doExport
调用链:ServiceBean#afterPropertiesSet#export#doExport
protected synchronized void doExport() {
//是否下线 执行了unexport
if (this.unexported) {
throw new IllegalStateException("Already unexported!");
//如果未发布
} else if (!this.exported) {
//设置为已发布
this.exported = true;
if (this.interfaceName != null && this.interfaceName.length() != 0) {
//检查并填充provider属性
this.checkDefault();
if (this.provider != null) {
/**
* 如果全局有配置始终会取到 外部源码可以看出来
* dubbo:service没有配置application 则获取provider的Application
*/
if (this.application == null) {
this.application = this.provider.getApplication();
}
//同上
if (this.module == null) {
this.module = this.provider.getModule();
}
//同上
if (this.registries == null) {
this.registries = this.provider.getRegistries();
}
//同上
if (this.monitor == null) {
this.monitor = this.provider.getMonitor();
}
//同上
if (this.protocols == null) {
this.protocols = this.provider.getProtocols();
}
}
//同上
if (this.module != null) {
//同上
if (this.registries == null) {
this.registries = this.module.getRegistries();
}
//同上
if (this.monitor == null) {
this.monitor = this.module.getMonitor();
}
}
//同上
if (this.application != null) {
//同上
if (this.registries == null) {
this.registries = this.application.getRegistries();
}
//同上
if (this.monitor == null) {
this.monitor = this.application.getMonitor();
}
}
/**
* 是否是泛型化暴露服务 可以查看具体文档
* http://dubbo.apache.org/zh-cn/docs/user/demos/generic-service.html
*/
if (this.ref instanceof GenericService) {
this.interfaceClass = GenericService.class;
if (StringUtils.isEmpty(this.generic)) {
//标识是泛型化暴露
this.generic = Boolean.TRUE.toString();
}
} else {
try {
/**
* 加载指定类 第二个参数为true则被加载的时候就初始化 如果没有指定类加载器 默认使用根加载器
*/
this.interfaceClass = Class.forName(this.interfaceName, true, Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException var5) {
throw new IllegalStateException(var5.getMessage(), var5);
}
/**
* 检查我们配置的method标签 在接口里面是否存在 如果不存在报错
* <dubbo:service interface="com.biz.soa.service.seckill.frontend.SoaSeckillFrontService" ref="soaSeckillFrontServiceImpl">
* <dubbo:method name="findByCategoryIds" timeout="2000"/>
* <dubbo:method name="seckillTabList" timeout="2000"/>
* <dubbo:method name="defaultSeckillProdcutList" timeout="2000"/>
* </dubbo:service>
*/
this.checkInterfaceAndMethods(this.interfaceClass, this.methods);
/**
* 检查是否配置ref标签 以及ref是否是interface实现类 如果不是抛出异常
*/
this.checkRef();
/**
* 标识非泛型化暴露
*/
this.generic = Boolean.FALSE.toString();
}
Class stubClass;
/**
* dubbo local机制 已经废弃 stub代替
*/
if (this.local != null) {
if ("true".equals(this.local)) {
this.local = this.interfaceName + "Local";
}
try {
stubClass = ClassHelper.forNameWithThreadContextClassLoader(this.local);
} catch (ClassNotFoundException var4) {
throw new IllegalStateException(var4.getMessage(), var4);
}
if (!this.interfaceClass.isAssignableFrom(stubClass)) {
throw new IllegalStateException("The local implementation class " + stubClass.getName() + " not implement interface " + this.interfaceName);
}
}
/**
* 用于服务容错 服务容错实现类全名称
*/
if (this.stub != null) {
if ("true".equals(this.stub)) {
this.stub = this.interfaceName + "Stub";
}
try {
stubClass = ClassHelper.forNameWithThreadContextClassLoader(this.stub);
} catch (ClassNotFoundException var3) {
throw new IllegalStateException(var3.getMessage(), var3);
}
/**
* stu类必须实现服务接口
*/
if (!this.interfaceClass.isAssignableFrom(stubClass)) {
throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + this.interfaceName);
}
}
/**
* 检验以下配置是否为空
* 并通过优先级读取填充 系统熟悉System.get properties文件
* dubbo.application.name
* dubbo.registry.address
*/
this.checkApplication();
this.checkRegistry();
this.checkProtocol();
appendProperties(this);
this.checkStubAndMock(this.interfaceClass);
if (this.path == null || this.path.length() == 0) {
this.path = this.interfaceName;
}
//发布服务
this.doExportUrls();
ProviderModel providerModel = new ProviderModel(this.getUniqueServiceName(), this, this.ref);
ApplicationModel.initProviderModel(this.getUniqueServiceName(), providerModel);
} else {
throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
}
}
}
LLL doExportUrls
调用链:
调用链:ServiceBean#afterPropertiesSet#export#doExport#doExportUrls
private void doExportUrls() {
/**
* 获得service bean的所有注册config信息 并转换为URL true表示提供者 fale表示消费者
*/
List<URL> registryURLs = this.loadRegistries(true);
/**
* 获得service bean的所有协议list
*/
Iterator i$ = this.protocols.iterator();
//遍历协议进行服务发布
while(i$.hasNext()) {
ProtocolConfig protocolConfig = (ProtocolConfig)i$.next();
this.doExportUrlsFor1Protocol(protocolConfig, registryURLs);
}
}
LLLL doExportUrlsFor1Protocol
调用链:ServiceBean#afterPropertiesSet#export#doExport#doExportUrls#doExportUrlsFor1Protocol
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
String name = protocolConfig.getName();
if (name == null || name.length() == 0) {
name = "dubbo";
}
/**
* 存储当前服务发布相关参数信息
* 数据例子:1
*/
Map<String, String> map = new HashMap();
map.put("side", "provider");
map.put("dubbo", Version.getVersion());
map.put("timestamp", String.valueOf(System.currentTimeMillis()));
if (ConfigUtils.getPid() > 0) {
map.put("pid", String.valueOf(ConfigUtils.getPid()));
}
/**
* 将当前serviceBean相关参数设置到 map * 逐级覆盖 methed标签优先级最高 最低是application 数据例子2
*/
appendParameters(map, this.application);
appendParameters(map, this.module);
appendParameters(map, this.provider, "default");
appendParameters(map, protocolConfig);
appendParameters(map, this);
/**
* methodConfig配置不为空
* 将methodConfig追加到参数map 如果跟全局配置一致 达到覆盖作用 如timeOut
* 数据例子2
*/
if (this.methods != null && !this.methods.isEmpty()) {
Iterator i$ = this.methods.iterator();
label188:
while(true) {
MethodConfig method;
List arguments;
do {
do {
if (!i$.hasNext()) {
break label188;
}
method = (MethodConfig)i$.next();
appendParameters(map, method, method.getName());
String retryKey = method.getName() + ".retry";
if (map.containsKey(retryKey)) {
String retryValue = (String)map.remove(retryKey);
if ("false".equals(retryValue)) {
map.put(method.getName() + ".retries", "0");
}
}
arguments = method.getArguments();
} while(arguments == null);
} while(arguments.isEmpty());
Iterator i$ = arguments.iterator();
while(true) {
ArgumentConfig argument;
Method[] methods;
do {
do {
while(true) {
if (!i$.hasNext()) {
continue label188;
}
argument = (ArgumentConfig)i$.next();
if (argument.getType() != null && argument.getType().length() > 0) {
methods = this.interfaceClass.getMethods();
break;
}
if (argument.getIndex() == -1) {
throw new IllegalArgumentException("argument config must set index or type attribute.eg: <dubbo:argument index='0' .../> or <dubbo:argument type=xxx .../>");
}
appendParameters(map, argument, method.getName() + "." + argument.getIndex());
}
} while(methods == null);
} while(methods.length <= 0);
for(int i = 0; i < methods.length; ++i) {
String methodName = methods[i].getName();
if (methodName.equals(method.getName())) {
Class<?>[] argtypes = methods[i].getParameterTypes();
if (argument.getIndex() != -1) {
if (!argtypes[argument.getIndex()].getName().equals(argument.getType())) {
throw new IllegalArgumentException("argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
}
appendParameters(map, argument, method.getName() + "." + argument.getIndex());
} else {
for(int j = 0; j < argtypes.length; ++j) {
Class<?> argclazz = argtypes[j];
if (argclazz.getName().equals(argument.getType())) {
appendParameters(map, argument, method.getName() + "." + j);
if (argument.getIndex() != -1 && argument.getIndex() != j) {
throw new IllegalArgumentException("argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
}
}
}
}
}
}
}
}
}
String contextPath;
/**
* 是否是泛型化发布
*/
if (ProtocolUtils.isGeneric(this.generic)) {
map.put("generic", this.generic);
map.put("methods", "*");
} else {
contextPath = Version.getVersion(this.interfaceClass, this.version);
if (contextPath != null && contextPath.length() > 0) {
map.put("revision", contextPath);
}
String[] methods = Wrapper.getWrapper(this.interfaceClass).getMethodNames();
if (methods.length == 0) {
logger.warn("NO method found in service interface " + this.interfaceClass.getName());
map.put("methods", "*");
} else {
map.put("methods", StringUtils.join(new HashSet(Arrays.asList(methods)), ","));
}
}
/**
* 是否开启token机制 默认为UUId
*/
if (!ConfigUtils.isEmpty(this.token)) {
if (ConfigUtils.isDefault(this.token)) {
map.put("token", UUID.randomUUID().toString());
} else {
map.put("token", this.token);
}
}
/**
* 如果协议为本地协议( injvm ),则设置 protocolConfig#register 属性为 false ,
* 表示不向注册中心注册服务,在 map 中存储键为 notify,值为 false,
* 表示当注册中心监听到服务提供者发生变化(服务提供者增加、服务提供者减少等)事件时不通知。
*/
if ("injvm".equals(protocolConfig.getName())) {
protocolConfig.setRegister(false);
map.put("notify", "false");
}
/**
* 设置协议的 contextPath,如果未配置,默认为 /interfacename
*/
contextPath = protocolConfig.getContextpath();
if ((contextPath == null || contextPath.length() == 0) && this.provider != null) {
contextPath = this.provider.getContextpath();
}
/**
* 解析服务提供者的IP地址与端口。并追加到map
*/
String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
Integer port = this.findConfigedPorts(protocolConfig, name, map);
/**
* 根据map和上下文组织Url
* 数据例子:3
*/
URL url = new URL(name, host, port, (contextPath != null && contextPath.length() != 0 ? contextPath + "/" : "") + this.path, map);
if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class).hasExtension(url.getProtocol())) {
url = ((ConfiguratorFactory)ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class).getExtension(url.getProtocol())).getConfigurator(url).configure(url);
}
/**
* 构建invoker实例
* 获取dubbo:service配置的scope属性
* 其可选值为 none (不暴露)、local (本地)、remote (远程),如果配置为 none,则不暴露。默认为 local。
*/
String scope = url.getParameter("scope");
if (!"none".toString().equalsIgnoreCase(scope)) {
/**
* 则先在本地暴露( injvm )
*/
if (!"remote".toString().equalsIgnoreCase(scope)) {
this.exportLocal(url);
}
/**
* 如果 scope 不为 local,则将服务暴露在远程。
*/
if (!"local".toString().equalsIgnoreCase(scope)) {
if (logger.isInfoEnabled()) {
logger.info("Export dubbo service " + this.interfaceClass.getName() + " to url " + url);
}
/**
* 如果注册中心不为空 则遍历注册中心 依次注册到注册中心
*/
if (registryURLs != null && !registryURLs.isEmpty()) {
Iterator i$ = registryURLs.iterator();
while(i$.hasNext()) {
URL registryURL = (URL)i$.next();
/**
* 如果 dubbo:service 的 dynamic 属性未配置,
* 尝试取 dubbo:registry 的 dynamic 属性,该属性的作用是否启用动态注册,如果设置为 false,服务注册后,
* 其状态显示为 disable,需要人工启用,当服务不可用时,也不会自动移除,同样需要人工处理,此属性不要在生产环境上配置
*/
url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
URL monitorUrl = this.loadMonitor(registryURL);
if (monitorUrl != null) {
url = url.addParameterAndEncoded("monitor", monitorUrl.toFullString());
}
if (logger.isInfoEnabled()) {
logger.info("Register dubbo service " + this.interfaceClass.getName() + " url " + url + " to registry " + registryURL);
}
/**
* 构建Invoker实例 dubbo远程调用实例
* spi
*private static final ProxyFactory proxyFactory = (ProxyFactory)ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
*这里取得的是com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory
* 数据例子4
*/
Invoker<?> invoker = proxyFactory.getInvoker(this.ref, this.interfaceClass, registryURL.addParameterAndEncoded("export", url.toFullString()));
//DelegateProviderMetaDataInvoker对象增加一层代理 内部保存源对象以及invoker 代理对象 执行器
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
/**
* 根据指定协议本地暴露和向注册中心注册服务
* SPI 这里取的是com.alibaba.dubbo.rpc.protocol.dubbo.ProtocolFilterWrapper和ProtocolListennerWrapper包装拦截器以及触发监听器 具体参考签名SPI
* 数据例子5
* private static final Protocol protocol = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
*/
Exporter<?> exporter = protocol.export(wrapperInvoker);
this.exporters.add(exporter);
}
} else {
Invoker<?> invoker = proxyFactory.getInvoker(this.ref, this.interfaceClass, url);
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = protocol.export(wrapperInvoker);
this.exporters.add(exporter);
}
}
}
this.urls.add(url);
}
数据例子1

数据例子2
<dubbo:service timeout="500" interface="com.biz.soa.service.seckill.frontend.SoaSeckillFrontService" ref="soaSeckillFrontServiceImpl"><dubbo:method name="findByCategoryIds" timeout="2000"/><dubbo:method name="seckillTabList" timeout="2000"/><dubbo:method name="defaultSeckillProdcutList" timeout="2000"/></dubbo:service
数据例子3

数据例子4
@SPI("javassist")
public interface ProxyFactory {
@Adaptive({"proxy"})
<T> T getProxy(Invoker<T> var1) throws RpcException;
@Adaptive({"proxy"})
<T> Invoker<T> getInvoker(T var1, Class<T> var2, URL var3) throws RpcException;
}

数据例子5
@SPI("dubbo")
public interface Protocol {
int getDefaultPort();
@Adaptive
<T> Exporter<T> export(Invoker<T> var1) throws RpcException;
@Adaptive
<T> Invoker<T> refer(Class<T> var1, URL var2) throws RpcException;
void destroy();
}

LLLLL findConfigedHosts
调用链:ServiceBean#afterPropertiesSet#export#doExport#doExportUrls#doExportUrlsFor1Protocol#findConfigedHosts
/**
* 获得暴露ip
* @param protocolConfig
* @param registryURLs
* @param map
* @return
*/
private String findConfigedHosts(ProtocolConfig protocolConfig, List<URL> registryURLs, Map<String, String> map) {
boolean anyhost = false;
/**
* 从系统变量->环境变量获取DUBBO_DUBBO_IP_TO_BIND的值 第一个DUBBO取得protocolConfig配置的name
*/
String hostToBind = this.getValueFromConfig(protocolConfig, "DUBBO_IP_TO_BIND");
//如果取到则校验有效性
if (hostToBind != null && hostToBind.length() > 0 && NetUtils.isInvalidLocalHost(hostToBind)) {
throw new IllegalArgumentException("Specified invalid bind ip from property:DUBBO_IP_TO_BIND, value:" + hostToBind);
} else {
if (hostToBind == null || hostToBind.length() == 0) {
//取protocol配置的host
hostToBind = protocolConfig.getHost();
//如果protocol没有渠道则取provider配置的ip
if (this.provider != null && (hostToBind == null || hostToBind.length() == 0)) {
hostToBind = this.provider.getHost();
}
//如果也没有取到
if (NetUtils.isInvalidLocalHost(hostToBind)) {
anyhost = true;
try {
//遍历网卡获取ip地址
hostToBind = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException var20) {
logger.warn(var20.getMessage(), var20);
}
//如果还不符合继续匹配 取依次取有效 注册中心地址
if (NetUtils.isInvalidLocalHost(hostToBind)) {
if (registryURLs != null && !registryURLs.isEmpty()) {
Iterator i$ = registryURLs.iterator();
label189:
while(true) {
URL registryURL;
do {
if (!i$.hasNext()) {
break label189;
}
registryURL = (URL)i$.next();
} while("multicast".equalsIgnoreCase(registryURL.getParameter("registry")));
try {
Socket socket = new Socket();
try {
SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort());
socket.connect(addr, 1000);
//建立连接成功表示有效 取这个注册中心地址
hostToBind = socket.getLocalAddress().getHostAddress();
break;
} finally {
try {
//释放连接
socket.close();
} catch (Throwable var18) {
;
}
}
} catch (Exception var21) {
logger.warn(var21.getMessage(), var21);
}
}
}
if (NetUtils.isInvalidLocalHost(hostToBind)) {
hostToBind = NetUtils.getLocalHost();
}
}
}
}
//将取到的bind ip追加到参数列表
map.put("bind.ip", hostToBind);
//从系统变量->环境变量获取DUBBO_DUBBO_IP_TO_REGISTRY 下面可以看到这个优先级最大如果没有渠道 则使用hostToBind
String hostToRegistry = this.getValueFromConfig(protocolConfig, "DUBBO_IP_TO_REGISTRY");
if (hostToRegistry != null && hostToRegistry.length() > 0 && NetUtils.isInvalidLocalHost(hostToRegistry)) {
throw new IllegalArgumentException("Specified invalid registry ip from property:DUBBO_IP_TO_REGISTRY, value:" + hostToRegistry);
} else {
if (hostToRegistry == null || hostToRegistry.length() == 0) {
hostToRegistry = hostToBind;
}
//是否取到host
map.put("anyhost", String.valueOf(anyhost));
return hostToRegistry;
}
}
}
LLLLL findConfigedPorts
调用链:ServiceBean#afterPropertiesSet#export#doExport#doExportUrls#doExportUrlsFor1Protocol#findConfigedPorts
/**
* 获得暴露的端口
* @param protocolConfig
* @param name
* @param map
* @return
*/
private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map<String, String> map) {
Integer portToBind = null;
/**
* 在系统变量|环境变量获得#{protocol.name.toUpperCase}_DUBBO_PORT_TO_BIND 绑定端口
*/
String port = this.getValueFromConfig(protocolConfig, "DUBBO_PORT_TO_BIND");
//如果配置的是有效的 string转为Integer
portToBind = this.parsePort(port);
//如果没取到
if (portToBind == null) {
//取protocol配置的Port
portToBind = protocolConfig.getPort();
//如果没取到则取provider配置
if (this.provider != null && (portToBind == null || portToBind == 0)) {
portToBind = this.provider.getPort();
}
//根据配置的协议 通过SPI获取对应的协议实现并获得默认port 这里name是dubbo
//数据例子:1
int defaultPort = ((Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name)).getDefaultPort();
//如果没获取到port则使用默认的
if (portToBind == null || portToBind == 0) {
portToBind = defaultPort;
}
//如果还是没取到 随机获取
if (portToBind == null || portToBind <= 0) {
portToBind = getRandomPort(name);
if (portToBind == null || portToBind < 0) {
portToBind = NetUtils.getAvailablePort(defaultPort);
putRandomPort(name, portToBind);
}
logger.warn("Use random available port(" + portToBind + ") for protocol " + name);
}
}
map.put("bind.port", String.valueOf(portToBind));
/**
* 获取系统变量|环境变量 #{protocol.name.toUpperCase}_DUBBO_PORT_TO_REGISTRY配置的port
* 此优先级最大
*/
String portToRegistryStr = this.getValueFromConfig(protocolConfig, "DUBBO_PORT_TO_REGISTRY");
//如果正常类型则转为Integer返回
Integer portToRegistry = this.parsePort(portToRegistryStr);
if (portToRegistry == null) {
portToRegistry = portToBind;
}
return portToRegistry;
}
数据例子1

JavassistProxyFactory
LLLLLL getInvoker
/**
* 代理实现
*/
public class JavassistProxyFactory extends AbstractProxyFactory {
public JavassistProxyFactory() {
}
/**
* jdk动态代理
* @param invoker
* @param interfaces
* @param <T>
* @return
*/
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
/**
* 采用javassis 动态生成类以及创建对象的生成代理 直接调用的方式 而不是使用jdk代理 反射调用方式 因为性能原因
* @param proxy
* @param type
* @param url
* @param <T>
* @return
*/
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf(36) < 0 ? proxy.getClass() : type);
return new AbstractProxyInvoker<T>(proxy, type, url) {
protected Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable {
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
}
RegistryProtocol
export
调用链:ServiceBean.afterPropertiesSet#ServiceConfig.export#ServiceConfig.doExport#ServiceConfig.doExportUrlsFor1Protocol#RegistryProtocol.export
public <T> Exporter<T> export(Invoker<T> originInvoker) throws RpcException {
/**
* 本地暴露服务
*/
RegistryProtocol.ExporterChangeableWrapper<T> exporter = this.doLocalExport(originInvoker);
/**
* 获取注册中心地址
* 数据例子1
*/
URL registryUrl = this.getRegistryUrl(originInvoker);
/**
* 获得注册中心实现类 这里为ZookeeperRegistry
* 数据例子2
*/
Registry registry = this.getRegistry(originInvoker);
/**
* 获取注册的服务地址
* 数据例子3
*/
URL registedProviderUrl = this.getRegistedProviderUrl(originInvoker);
boolean register = registedProviderUrl.getParameter("register", true);
ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registedProviderUrl);
if (register) {
this.register(registryUrl, registedProviderUrl);
ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true);
}
URL overrideSubscribeUrl = this.getSubscribedOverrideUrl(registedProviderUrl);
RegistryProtocol.OverrideListener overrideSubscribeListener = new RegistryProtocol.OverrideListener(overrideSubscribeUrl, originInvoker);
this.overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
//像注册中心发布自己
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
return new RegistryProtocol.DestroyableExporter(exporter, originInvoker, overrideSubscribeUrl, registedProviderUrl);
}
数据例子1

数据例子2

数据例子3

doLocalExport
private <T> RegistryProtocol.ExporterChangeableWrapper<T> doLocalExport(Invoker<T> originInvoker) {
String key = this.getCacheKey(originInvoker);
RegistryProtocol.ExporterChangeableWrapper<T> exporter = (RegistryProtocol.ExporterChangeableWrapper)this.bounds.get(key);
if (exporter == null) {
Map var4 = this.bounds;
synchronized(this.bounds) {
exporter = (RegistryProtocol.ExporterChangeableWrapper)this.bounds.get(key);
if (exporter == null) {
Invoker<?> invokerDelegete = new RegistryProtocol.InvokerDelegete(originInvoker, this.getProviderUrl(originInvoker));
//这里会调用DubboProtocol 暴露自己 this.protocol.export(invokerDelegete)
exporter = new RegistryProtocol.ExporterChangeableWrapper(this.protocol.export(invokerDelegete), originInvoker);
this.bounds.put(key, exporter);
}
}
}
return exporter;
}
dubbo-源码阅读之服务发布的更多相关文章
- dubbo 源码学习1 服务发布机制
1.源码版本:2.6.1 源码demo中采用的是xml式的发布方式,在dubbo的 DubboNamespaceHandler 中定义了Spring Framework 的扩展标签,即 <dub ...
- dubbo源码阅读之服务导出
dubbo服务导出 常见的使用dubbo的方式就是通过spring配置文件进行配置.例如下面这样 <?xml version="1.0" encoding="UTF ...
- dubbo源码阅读之服务目录
服务目录 服务目录对应的接口是Directory,这个接口里主要的方法是 List<Invoker<T>> list(Invocation invocation) throws ...
- dubbo源码阅读之服务引入
服务引入 服务引入使用reference标签来对要引入的服务进行配置,包括服务的接口 ,名称,init,check等等配置属性. 在DubboNamespaceHandler中,我们可以看到refer ...
- 【Dubbo源码阅读系列】服务暴露之远程暴露
引言 什么叫 远程暴露 ?试着想象着这么一种场景:假设我们新增了一台服务器 A,专门用于发送短信提示给指定用户.那么问题来了,我们的 Message 服务上线之后,应该如何告知调用方服务器,服务器 A ...
- 【Dubbo源码阅读系列】服务暴露之本地暴露
在上一篇文章中我们介绍 Dubbo 自定义标签解析相关内容,其中我们自定义的 XML 标签 <dubbo:service /> 会被解析为 ServiceBean 对象(传送门:Dubbo ...
- 【Dubbo源码阅读系列】之远程服务调用(上)
今天打算来讲一讲 Dubbo 服务远程调用.笔者在开始看 Dubbo 远程服务相关源码的时候,看的有点迷糊.后来慢慢明白 Dubbo 远程服务的调用的本质就是动态代理模式的一种实现.本地消费者无须知道 ...
- Dubbo源码学习之-服务导出
前言 忙的时候,会埋怨学习的时间太少,缺少个人的空间,于是会争分夺秒的工作.学习.而一旦繁忙的时候过去,有时间了之后,整个人又会不自觉的陷入一种懒散的状态中,时间也显得不那么重要了,随便就可以浪费掉几 ...
- 【Dubbo源码阅读系列】之 Dubbo SPI 机制
最近抽空开始了 Dubbo 源码的阅读之旅,希望可以通过写文章的方式记录和分享自己对 Dubbo 的理解.如果在本文出现一些纰漏或者错误之处,也希望大家不吝指出. Dubbo SPI 介绍 Java ...
- Dubbo源码阅读顺序
转载: https://blog.csdn.net/heroqiang/article/details/85340958 Dubbo源码解析之配置解析篇,主要内容是<dubbo:service/ ...
随机推荐
- Mysql语句优化建议
一.建立索引 1)考虑在 where 及 order by 涉及的列上建立索引 2)对于模糊查询, 建立全文索引 3)对于多主键查询,建立组合索引 二.避免陷阱 然而,一些情况下可能使索引无效: 1) ...
- Nginx的应用之安装配置
一.Nginx简述 Nginx是一个开源且高性能.可靠的Http Web服务.代理服务. 开源: 直接获取源代码 高性能: 支持海量并发 可靠: 服务稳定 我们为什么选择 Nginx服务 Nginx非 ...
- java应用之solr入门篇
前言 solr是apache项目的一款全文搜索应用. 官方文档http://lucene.apache.org/solr/guide/6_6/ 入门流程 1.安装 ---> 2.启动 - ...
- 西电源ubuntu12
deb http://linux.xidian.edu.cn/mirrors/ubuntu/ precise main restricted universe multiverse #deb-src ...
- double中首字母大写与小写的区别
Double 是类 double是基础数据类型.Double类型是double的包装类.Double 和double之间的相互转化称为自动拆箱和自动装箱.如果从对象角度理解,那么Double就是对象, ...
- 【leetcode】921. Minimum Add to Make Parentheses Valid
题目如下: 解题思路:上周都在忙着参加CTF,没时间做题,今天来更新一下博客吧.括号问题在leetcode中出现了很多,本题的解题思路和以前的括号问题一样,使用栈.遍历Input,如果是'('直接入栈 ...
- python字符转化
int(x [,base ]) 将x转换为一个整数 long(x [,base ]) 将x转换为一个长整数 float(x) 将x转换到一个浮点数 complex(real [,imag ]) 创建一 ...
- 深度解析双十一背后的阿里云 Redis 服务
摘要: Redis是一个使用范围很广的NOSQL数据库,阿里云Redis同时在公有云和阿里集团内部进行服务,本文介绍了阿里云Redis双11的一些业务场景:微淘社区之亿级关系链存储.天猫直播之评论商品 ...
- 那些长短不一的PCI-E插槽都有什么不一样?
https://www.ednchina.com/news/20171121-PCI-E.html 时间:2017-11-21 目前PCI-E插槽已经成为了主板上的主力扩展插槽,除了显卡会用到P ...
- Cisco基础(五):配置静态NAT、配置端口映射、配置动态NAT、PAT配置、办公区Internet的访问
一.配置静态NAT 目标: 随着接入Internet的计算机数量的不断猛增,IP地址资源也就愈加显得捉襟见肘.事实上,除了中国教育和科研计算机网(CERNET)外,一般用户几乎申请不到整段的C类IP地 ...