文章目录
dubbo源码学习历史文章
DUBBO源码学习(一)spi机制
DUBBO源码学习(二)注册中心源码解析
一、DUBBO服务暴露
spring ioc容器启动的时候会同时启动dubbo容器,从2.7.5版本后增加了DubboBootstrapApplicationListener类,负责监听dubbo容器的启动事件:
/**
* The {@link ApplicationListener} for {@link DubboBootstrap}'s lifecycle when the {@link ContextRefreshedEvent}
* and {@link ContextClosedEvent} raised
*
* @since 2.7.5
*/
public class DubboBootstrapApplicationListener extends OnceApplicationContextEventListener implements Ordered {
/**
* The bean name of {@link DubboBootstrapApplicationListener}
*
* @since 2.7.6
*/
public static final String BEAN_NAME = "dubboBootstrapApplicationListener";
private final DubboBootstrap dubboBootstrap;
public DubboBootstrapApplicationListener() {
this.dubboBootstrap = DubboBootstrap.getInstance();
}
public DubboBootstrapApplicationListener(ApplicationContext applicationContext) {
super(applicationContext);
this.dubboBootstrap = DubboBootstrap.getInstance();
DubboBootstrapStartStopListenerSpringAdapter.applicationContext = applicationContext;
}
/**
* Spring ioc 容器事件监听
* @param event
*/
@Override
public void onApplicationContextEvent(ApplicationContextEvent event) {
if (DubboBootstrapStartStopListenerSpringAdapter.applicationContext == null) {
DubboBootstrapStartStopListenerSpringAdapter.applicationContext = event.getApplicationContext();
}
//容器刷新事件
if (event instanceof ContextRefreshedEvent) {
onContextRefreshedEvent((ContextRefreshedEvent) event);
//容器关闭事件
} else if (event instanceof ContextClosedEvent) {
onContextClosedEvent((ContextClosedEvent) event);
}
}
private void onContextRefreshedEvent(ContextRefreshedEvent event) {
dubboBootstrap.start();
}
private void onContextClosedEvent(ContextClosedEvent event) {
DubboShutdownHook.getDubboShutdownHook().run();
}
@Override
public int getOrder() {
return LOWEST_PRECEDENCE;
}
}
可以看到DubboBootstrapApplicationListener继承了OnceApplicationContextEventListener类,主要是实现了onApplicationContextEvent 方法,通过此方法监听了同期的刷新与关闭事件,同时也实现了Ordered接口,执行的顺序为最低顺序。
1.1、DUBBO容器的启动
DUBBO容器的启动是由DubboBootstrap来执行的。DubboBootstrap中有比较重要的两个对象,一个是ConfigManager,一个是Environment。
从上图可以看出,配置加载大概分为两个阶段:
- 第一阶段为DubboBootstrap初始化之前,在Spring context启动时解析处理XML配置/注解配置/Java-config 或者是执行API配置代码,创建config bean并且加入到ConfigManager中。
- 第二阶段为DubboBootstrap初始化过程,从配置中心读取外部配置,依次处理实例级属性配置和应用级属性配置,最后刷新所有配置实例的属性,也就是属性覆盖。
- ConfigManager:顾名思义是一个配置中心,有RegistryConfig(注册中心配置)、ConsumerConfig(消费者配置)、ProtocolConfig(协议配置)、ProviderConfig(服务提供者配置)、ApplicationConfig(容器配置)、MonitorConfig(监控中心配置)。
- Environment:Environment主要处理的与系统配置相关,比如Java系统配置,以及配置中心的配置。
DUBBO容器的启动是通过start方法执行的:
public class DubboBootstrap {
/**
* Dubbo的启动
*/
public DubboBootstrap start() {
//通过cas原子操作代替加锁
if (started.compareAndSet(false, true)) {
ready.set(false);
//初始化操作
initialize();
if (logger.isInfoEnabled()) {
logger.info(NAME + " is starting...");
}
// Dubbo Services服务暴露
exportServices();
// 是否配置了元数据中心的url
if (!isOnlyRegisterProvider() || hasExportedServices()) {
// export MetadataService 暴露本地的元数据服务
exportMetadataService();
// 将本地serviceInstance注册到注册中心
registerServiceInstance();
}
//处理ReferenceConfig对象
referServices();
//service异步暴露后的返回处理
if (asyncExportingFutures.size() > 0) {
new Thread(() -> {
try {
this.awaitFinish();
} catch (Exception e) {
logger.warn(NAME + " exportAsync occurred an exception.");
}
ready.set(true);
if (logger.isInfoEnabled()) {
logger.info(NAME + " is ready.");
}
//spi机制,获取所有DubboBootstrapStartStopListener,本包下会拿到DubboBootstrapStartStopListenerSpringAdapter类
ExtensionLoader<DubboBootstrapStartStopListener> exts = getExtensionLoader(DubboBootstrapStartStopListener.class);
//发布DubboBootstrapStatedEvent事件
exts.getSupportedExtensionInstances().forEach(ext -> ext.onStart(this));
}).start();
} else {
//service同步暴露处理,与上一步类似
ready.set(true);
if (logger.isInfoEnabled()) {
logger.info(NAME + " is ready.");
}
ExtensionLoader<DubboBootstrapStartStopListener> exts = getExtensionLoader(DubboBootstrapStartStopListener.class);
exts.getSupportedExtensionInstances().forEach(ext -> ext.onStart(this));
}
if (logger.isInfoEnabled()) {
logger.info(NAME + " has started.");
}
}
return this;
}
/**
* 暴露服务
*/
private void exportServices() {
// 创建的每个ServiceConfig对象都添加到configManager,下面获取所有的ServiceConfig对象并遍历
configManager.getServices().forEach(sc -> {
ServiceConfig serviceConfig = (ServiceConfig) sc;
serviceConfig.setBootstrap(this);
//异步暴露,使用线程池暴露服务
if (exportAsync) {
ExecutorService executor = executorRepository.getServiceExporterExecutor();
Future<?> future = executor.submit(() -> {
try {
//暴露服务的动作
exportService(serviceConfig);
} catch (Throwable t) {
logger.error("export async catch error : " + t.getMessage(), t);
}
});
asyncExportingFutures.add(future);
} else {
//暴露服务
exportService(serviceConfig);
}
});
}
private void exportService(ServiceConfig sc) {
if (exportedServices.containsKey(sc.getServiceName())) {
throw new IllegalStateException("There are multiple ServiceBean instances with the same service name: [" +
sc.getServiceName() + "], instances: [" +
exportedServices.get(sc.getServiceName()).toString() + ", " +
sc.toString() + "]. Only one service can be exported for the same triple (group, interface, version), " +
"please modify the group or version if you really need to export multiple services of the same interface.");
}
//服务暴露
sc.export();
//服务暴露后放入缓存,防止重复暴露
exportedServices.put(sc.getServiceName(), sc);
}
}
二、serviceConfig服务暴露
老图新用,可以看到dubbo的十层协议的第二层,就是serviceConfig.export()。通过serviceConfig.export()方法,我们可以将dubbo的服务通过不同的protocol暴露到注册中心中。
public class ServiceConfig<T> extends ServiceConfigBase<T> {
@Override
public synchronized void export() {
if (bootstrap == null) {
bootstrap = DubboBootstrap.getInstance();
if (null != this.getRegistry()) {
//获取注册中心,上一篇文章有分析如何获取注册中心
bootstrap.registries(this.getRegistries());
}
//初始化操作
bootstrap.initialize();
}
//检查并且更新配置
checkAndUpdateSubConfigs();
initServiceMetadata(provider);
serviceMetadata.setServiceType(getInterfaceClass());
serviceMetadata.setTarget(getRef());
serviceMetadata.generateServiceKey();
if (!shouldExport()) {
return;
}
//延时暴露
if (shouldDelay()) {
DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);
} else {
doExport();
}
exported();
}
}
2.1、dubbo服务配置初始化
在boostrap初始化的时候,需要执行initialize方法,可以看到这都是dubbo服务相关配置的初始化操作。
/**
* 初始化操作
*/
public void initialize() {
//原子性操作,目的是为了只初始化一次
if (!initialized.compareAndSet(false, true)) {
return;
}
//初始化FrameworkExt实现类,这里会调用Environment的initialize方法
ApplicationModel.initFrameworkExts();
//启动配置中心
startConfigCenter();
//加载远程配置
loadRemoteConfigs();
//验证全局配置
checkGlobalConfigs();
//启动元数据配置中心
// @since 2.7.8
startMetadataCenter();
//初始化dubbo本地服务
initMetadataService();
if (logger.isInfoEnabled()) {
logger.info(NAME + " has been initialized!");
}
}
2.2、checkAndUpdateSubConfigs()
这个方法看起来只是一个简单的方法校验,但是实际上里面做了很多的东西,包括泛化调用的判断以及本地存根的判断等。
private void checkAndUpdateSubConfigs() {
// 使用显示配置的provider、module、application 来进行一些全局配置,其优先级为 ServiceConfig > provider > module > application
completeCompoundConfigs();
// 校验配置中心。这里会通过ConfigManager启动配置中心,并加载外部化配置。
checkDefault();
// 检查protocol是否存在,不存在则使用默认dubbo协议
checkProtocol();
// spi获取自定义的ConfigInitializer 可以通过此方式加载自定义serviceConfig配置
List<ConfigInitializer> configInitializers = ExtensionLoader.getExtensionLoader(ConfigInitializer.class)
.getActivateExtension(URL.valueOf(CONFIG_INITIALIZER_PROTOCOL), (String[]) null);
configInitializers.forEach(e -> e.initServiceConfig(this));
// 如果协议不是inJvm,检查address的合法性
if (!isOnlyInJvm()) {
checkRegistry();
}
//将Environment变量注入到当前对象的配置中
this.refresh();
//接口参数的校验
if (StringUtils.isEmpty(interfaceName)) {
throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
}
//实现的泛化调用的处理
if (ref instanceof GenericService) {
interfaceClass = GenericService.class;
if (StringUtils.isEmpty(generic)) {
generic = TRUE_VALUE;
}
} else {
try {
//反射获取接口
interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
.getContextClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
//校验接口方法的存在于配置
checkInterfaceAndMethods(interfaceClass, getMethods());
// 校验实现类的存在于是否继承该接口
checkRef();
generic = FALSE_VALUE;
}
//已过时 废弃
if (local != null) {
if (TRUE_VALUE.equals(local)) {
local = interfaceName + LOCAL_SUFFIX;
}
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);
}
}
/*
* 本地存根 配置<dubbo:service interface="com.foo.BarService" stub="true" />
* 远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑,
* 比如:做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 API 中带上 Stub,
* 客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub 1,然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy。
*/
if (stub != null) {
if (TRUE_VALUE.equals(stub)) {
stub = interfaceName + STUB_SUFFIX;
}
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);
}
}
checkStubAndLocal(interfaceClass);
ConfigValidationUtils.checkMock(interfaceClass, this);
ConfigValidationUtils.validateServiceConfig(this);
postProcessConfig();
}
private void postProcessConfig() {
//spi,自定义方法
List<ConfigPostProcessor> configPostProcessors = ExtensionLoader.getExtensionLoader(ConfigPostProcessor.class)
.getActivateExtension(URL.valueOf(CONFIG_POST_PROCESSOR_PROTOCOL), (String[]) null);
configPostProcessors.forEach(component -> component.postProcessServiceConfig(this));
}
可以看到仅仅这一处方法,就有两个地方用到spi加载自定义方法执行的方式,体现了dubbo的高度灵活性。
再简单讲下stub,其工作流程其实与apo的流程类似:
- 服务消费者发起调用
- 如果服务消费者端存在本地存根 Stub 的话,会先执行本地存根
- 本地存根 Stub 持有远程服务的 Proxy 对象,Stub 在执行的时候,会先执行自己的逻辑 (before),然后通过 Proxy 发起远程调用,最后在返回过程之前也会执行自己的逻辑 (after-returning)
- 如果远程服务的 Proxy 对象在执行过程中抛出了 exception,会执行服务消费端的本地伪装 Mock 的逻辑 (after-throwing),返回容错数据,从而达到服务降级的目的
2.3、doExport -> doExportUrls服务暴露
protected synchronized void doExport() {
if (unexported) {
throw new IllegalStateException("The service " + interfaceClass.getName() + " has already unexported!");
}
if (exported) {
return;
}
exported = true;
if (StringUtils.isEmpty(path)) {
path = interfaceName;
}
doExportUrls();
bootstrap.setReady(true);
}
private void doExportUrls() {
//存储了所有服务端发布的服务、客户端需要访问的服务,通过ServiceRepository可以获取所有本dubbo实例发布的服务和引用的服务。
ServiceRepository repository = ApplicationModel.getServiceRepository();
//存储了服务接口的Class对象,接口名,服务接口每个方法的名字、入参类型、返回值类型等详细信息.
ServiceDescriptor serviceDescriptor = repository.registerService(getInterfaceClass());
//存储了provider相关信息
repository.registerProvider(
getUniqueServiceName(),
ref,
serviceDescriptor,
this,
serviceMetadata
);
// 获取所有注册中心的URL
List<URL> registryURLs = ConfigValidationUtils.loadRegistries(this, true);
int protocolConfigNum = protocols.size();
//所有协议处理
for (ProtocolConfig protocolConfig : protocols) {
// pathKey = group/contextpath/path:version
String pathKey = URL.buildKey(getContextPath(protocolConfig)
.map(p -> p + "/" + path)
.orElse(path), group, version);
repository.registerService(pathKey, interfaceClass);
// 根据协议暴露,注册到各个注册中心
doExportUrlsFor1Protocol(protocolConfig, registryURLs, protocolConfigNum);
}
}
2.4、doExportUrlsFor1Protocol根据不同协议暴露服务
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs, int protocolConfigNum) {
String name = protocolConfig.getName();
if (StringUtils.isEmpty(name)) {
name = DUBBO;
}
//参数配置
Map<String, String> map = new HashMap<String, String>();
map.put(SIDE_KEY, PROVIDER_SIDE);
ServiceConfig.appendRuntimeParameters(map);
AbstractConfig.appendParameters(map, getMetrics());
AbstractConfig.appendParameters(map, getApplication());
AbstractConfig.appendParameters(map, getModule());
AbstractConfig.appendParameters(map, provider);
AbstractConfig.appendParameters(map, protocolConfig);
AbstractConfig.appendParameters(map, this);
MetadataReportConfig metadataReportConfig = getMetadataReportConfig();
if (metadataReportConfig != null && metadataReportConfig.isValid()) {
map.putIfAbsent(METADATA_KEY, REMOTE_METADATA_STORAGE_TYPE);
}
//methods 配置解析,<dubbo:method />
if (CollectionUtils.isNotEmpty(getMethods())) {
for (MethodConfig method : getMethods()) {
// 添加 MethodConfig 对象的字段信息到 map 中,键 = 方法名.属性名。
// 比如存储 <dubbo:method name="sayHello" retries="2"> 对应的 MethodConfig,
// 键 = sayHello.retries,map = {"sayHello.retries": 2}
AbstractConfig.appendParameters(map, method, method.getName());
String retryKey = method.getName() + RETRY_SUFFIX;
if (map.containsKey(retryKey)) {
String retryValue = map.remove(retryKey);
// 设置重试次数
if (FALSE_VALUE.equals(retryValue)) {
map.put(method.getName() + RETRIES_SUFFIX, ZERO_VALUE);
}
}
List<ArgumentConfig> arguments = method.getArguments();
if (CollectionUtils.isNotEmpty(arguments)) {
for (ArgumentConfig argument : arguments) {
if (argument.getType() != null && argument.getType().length() > 0) {
//所有的接口方法
Method[] methods = interfaceClass.getMethods();
if (methods.length > 0) {
for (int i = 0; i < methods.length; i++) {
String methodName = methods[i].getName();
// target the method, and get its signature
if (methodName.equals(method.getName())) {
Class<?>[] argtypes = methods[i].getParameterTypes();
// argument.getIndex() 默认值是 -1 ,如果这里不为-1,说明用户不仅设置了type还设置了index
if (argument.getIndex() != -1) {
// 检测 ArgumentConfig 中的 type 属性与方法参数列表
if (argtypes[argument.getIndex()].getName().equals(argument.getType())) {
// 添加 ArgumentConfig信息到缓存
AbstractConfig
.appendParameters(map, argument, method.getName() + "." + argument.getIndex());
} else {
throw new IllegalArgumentException(
"Argument config error : the index attribute and type attribute not match :index :" +
argument.getIndex() + ", type:" + argument.getType());
}
} else {
// index =-1 则需要遍历所有参数列表,获取到指定type 类型的参数
for (int j = 0; j < argtypes.length; j++) {
// 从参数类型列表中查找类型名称为 argument.type 的参数
Class<?> argclazz = argtypes[j];
if (argclazz.getName().equals(argument.getType())) {
AbstractConfig.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());
}
}
}
}
}
}
}
} else if (argument.getIndex() != -1) {
AbstractConfig.appendParameters(map, argument, method.getName() + "." + argument.getIndex());
} else {
throw new IllegalArgumentException(
"Argument config must set index or type attribute.eg: <dubbo:argument index='0' .../> or <dubbo:argument type=xxx .../>");
}
}
}
} // end of methods for
}
//如果是泛化调用,设置对于应参数
if (ProtocolUtils.isGeneric(generic)) {
map.put(GENERIC_KEY, generic);
map.put(METHODS_KEY, ANY_VALUE);
} else {
//版本
String revision = Version.getVersion(interfaceClass, version);
if (revision != null && revision.length() > 0) {
map.put(REVISION_KEY, revision);
}
// 获取所有方法,使用逗号拼接存入缓存
String[] methods = methods(this.interfaceClass);
if (methods.length == 0) {
logger.warn("No method found in service interface " + interfaceClass.getName());
map.put(METHODS_KEY, ANY_VALUE);
} else {
map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
}
}
/**
* Here the token value configured by the provider is used to assign the value to ServiceConfig#token
*/
//如果接口使用了token验证,则对token处理
if (ConfigUtils.isEmpty(token) && provider != null) {
token = provider.getToken();
}
if (!ConfigUtils.isEmpty(token)) {
if (ConfigUtils.isDefault(token)) {
map.put(TOKEN_KEY, UUID.randomUUID().toString());
} else {
map.put(TOKEN_KEY, token);
}
}
//init serviceMetadata attachments
serviceMetadata.getAttachments().putAll(map);
// 获取dubbo暴露的地址端口
String host = findConfigedHosts(protocolConfig, registryURLs, map);
Integer port = findConfigedPorts(protocolConfig, name, map, protocolConfigNum);
//拼接url
URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);
// SPI处理,可以自定义url拼接规则
if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.hasExtension(url.getProtocol())) {
url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.getExtension(url.getProtocol()).getConfigurator(url).configure(url);
}
String scope = url.getParameter(SCOPE_KEY);
// scope 为SCOPE_NONE 则不导出服务
if (!SCOPE_NONE.equalsIgnoreCase(scope)) {
// scope 不为SCOPE_NONE 则导出本地服务
if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
// 本地服务导出
exportLocal(url);
}
//scope 不为SCOPE_LOCAL则导出远程服务
if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
// 需要判断服务注册中心是否存在
if (CollectionUtils.isNotEmpty(registryURLs)) {
for (URL registryURL : registryURLs) {
if (SERVICE_REGISTRY_PROTOCOL.equals(registryURL.getProtocol())) {
url = url.addParameterIfAbsent(REGISTRY_TYPE_KEY, SERVICE_REGISTRY_TYPE);
}
//if protocol is only injvm ,not register
if (LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
continue;
}
// 是否动态,该字段标识是有自动管理服务提供者的上线和下线,若为false 则人工管理
url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));
// 监控中心配置
URL monitorUrl = ConfigValidationUtils.loadMonitor(this, registryURL);
if (monitorUrl != null) {
url = url.addParameterAndEncoded(MONITOR_KEY, monitorUrl.toFullString());
}
if (logger.isInfoEnabled()) {
if (url.getParameter(REGISTER_KEY, true)) {
logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " +
registryURL);
} else {
logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
}
}
// 代理配置解析
String proxy = url.getParameter(PROXY_KEY);
if (StringUtils.isNotEmpty(proxy)) {
registryURL = registryURL.addParameter(PROXY_KEY, proxy);
}
// 远程服务导出,把实现类包装成invoker
Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass,
registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
// DelegateProviderMetaDataInvoker 用于持有 Invoker 和 ServiceConfig
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
// 暴露服务,并生成 Exporter,注册到注册中心
Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);
exporters.add(exporter);
}
} else {
if (logger.isInfoEnabled()) {
logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
}
// 如果没有注册中心,则采用直连方式,即没有服务注册和监听的过程
Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, url);
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
//暴露服务,注册到注册中心
Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);
exporters.add(exporter);
}
// 元数据存储
MetadataUtils.publishServiceDefinition(url);
}
}
this.urls.add(url);
}
方法比较长,值得关注的有两个方法:
- 获取invoker:Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, url);
- 服务暴露:Exporter<?> exporter = PROTOCOL.export(wrapperInvoker)
2.5、获取invoker
在 Dubbo 中,Invoker 是一个非常重要的模型。在服务提供端,以及服务引用端均会出现 Invoker。Dubbo 官方文档中对
Invoker 进行了说明,这里引用一下。 Invoker 是实体域,它是 Dubbo
的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起 invoke
调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。
主要是通过ProxyFactory接口去获取invoker,默认的实现类是JavassistProxyFactory
public class JavassistProxyFactory extends AbstractProxyFactory {
@Override
@SuppressWarnings("unchecked")
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
@Override
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// 为目标类创建 Wrapper
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
// 创建匿名 Invoker 类对象,并实现 doInvoke 方法。
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
// 调用 Wrapper 的 invokeMethod 方法,invokeMethod 最终会调用目标方法
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
}
可以看到,AbstractProxyInvoker通过invoker方法调用了 Wrapper 的 invokeMethod 方法,invokeMethod 最终会调用目标方法,并返回了wapper后的Invoker对象,而且可以看到最后返回的是一个包装后的CompletableFuture对象,可以进行异步处理:
public abstract class AbstractProxyInvoker<T> implements Invoker<T> {
/**
* invoke 执行方法
* @param invocation
* @return
* @throws RpcException
*/
@Override
public Result invoke(Invocation invocation) throws RpcException {
try {
// wrapper的invokeMethod方法
Object value = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments());
CompletableFuture<Object> future = wrapWithFuture(value);
CompletableFuture<AppResponse> appResponseFuture = future.handle((obj, t) -> {
AppResponse result = new AppResponse(invocation);
if (t != null) {
if (t instanceof CompletionException) {
result.setException(t.getCause());
} else {
result.setException(t);
}
} else {
result.setValue(obj);
}
return result;
});
return new AsyncRpcResult(appResponseFuture, invocation);
} catch (InvocationTargetException e) {
if (RpcContext.getContext().isAsyncStarted() && !RpcContext.getContext().stopAsync()) {
logger.error("Provider async started, but got an exception from the original method, cannot write the exception back to consumer because an async result may have returned the new thread.", e);
}
return AsyncRpcResult.newDefaultAsyncResult(null, e.getTargetException(), invocation);
} catch (Throwable e) {
throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
}
2.6、远程服务暴露
Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);
获取到上一步获取的wapper后,就可以开始进行远程服务的暴露,PROTOCOL.export(wrapperInvoker)会调用到Protocol接口的export方法。首先会调用到RegistryProtocol.export()
public class RegistryProtocol implements Protocol {
/**
* 暴露服务
*/
@Override
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
//注册中心url以 zookeeper 注册中心为例,得到的示例 URL 如下:
// zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.2&export=dubbo%3A%2F%2F172.17.48.52%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider
URL registryUrl = getRegistryUrl(originInvoker);
//导出服务url
URL providerUrl = getProviderUrl(originInvoker);
// 获取订阅 URL,比如:
// provider://172.17.48.52:20880/com.alibaba.dubbo.demo.DemoService?category=configurators&check=false&anyhost=true&application=demo-provider&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello
final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
// 创建监听器
final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
// 启动netty服务导出服务
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);
//获取注册中心实现类,如ZookeeperRegistry
final Registry registry = getRegistry(originInvoker);
// 获取已注册的服务提供者 URL,比如:
// dubbo://172.17.48.52:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello
final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);
// 标注是否需要延期发布
boolean register = providerUrl.getParameter(REGISTER_KEY, true);
if (register) {
//注册服务
registry.register(registeredProviderUrl);
}
// register stated url on provider model
registerStatedUrl(registryUrl, registeredProviderUrl, register);
exporter.setRegisterUrl(registeredProviderUrl);
// 向注册中心进行订阅 override 数据
exporter.setSubscribeUrl(overrideSubscribeUrl);
// 注册中心订阅,上一篇有分析
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
//监听器通知,可以通过spi自定义
notifyExport(exporter);
//Ensure that a new exporter instance is returned every time export
return new DestroyableExporter<>(exporter);
}
}
对于服务注册的这块内容,可以参考上一篇文章。