文章目录
DUBBO源码学习(一)spi机制
DUBBO源码学习(二)注册中心源码解析
DUBBO源码学习(三)v2.7.8-服务的调用过程
本文基于dubbo-v2.7.8版本。
一、服务引用的过程
Dubbo 服务引用的时机是通过 Spring 容器调用 ReferenceBean 的 afterPropertiesSet 方法时引用服务。在引用的过程中,首先Spring 会调用 getObject 方法,并由该方法执行服务引用逻辑。服务的运用有三种,分别是
- 引用本地服务(jvm)
- 直连远程服务
- 通过注册中心调用远程服务
在引用的过程中,dubbo会生成一个invoker,如果是多个注册中心,则是一组invoker,并且会合并多个容错cluster成最终的invoker。最终生成的invoker会通过ProxyFactory 为服务接口生成代理类,并让代理Proxy类去调用 Invoker 逻辑,来避免对业务代码的侵入。
二、源码分析
2.1、ReferenceBean初始化
ReferenceBean实现了 InitializingBean,在Bean的初始化的时候会调用afterPropertiesSet方法:
public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean,
ApplicationContextAware, InitializingBean, DisposableBean {
public void afterPropertiesSet() throws Exception {
// Initializes Dubbo's Config Beans before @Reference bean autowiring
prepareDubboConfigBeans();
// 懒加载.
if (init == null) {
init = false;
}
// eager init if necessary.
if (shouldInit()) {
getObject();
}
}
/**
* 为了保证Initializes dubbo配置在@Reference bean 注入之前
* beansOfTypeIncludingAncestors方法获取spring容器中第二个入参要求类型的所有bean对象。dubbo就是通过这个方法保证了在调用DubboBootstrap.initialize方法之前,所有的配置对象都已经创建完毕。
*/
private void prepareDubboConfigBeans() {
// Refactor 2.7.9
final boolean includeNonSingletons = true;
final boolean allowEagerInit = false;
beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, includeNonSingletons, allowEagerInit);
beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, includeNonSingletons, allowEagerInit);
beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, includeNonSingletons, allowEagerInit);
beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, includeNonSingletons, allowEagerInit);
beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, includeNonSingletons, allowEagerInit);
beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, includeNonSingletons, allowEagerInit);
beansOfTypeIncludingAncestors(applicationContext, ConsumerConfig.class, includeNonSingletons, allowEagerInit);
beansOfTypeIncludingAncestors(applicationContext, ConfigCenterBean.class, includeNonSingletons, allowEagerInit);
beansOfTypeIncludingAncestors(applicationContext, MetadataReportConfig.class, includeNonSingletons, allowEagerInit);
beansOfTypeIncludingAncestors(applicationContext, MetricsConfig.class, includeNonSingletons, allowEagerInit);
beansOfTypeIncludingAncestors(applicationContext, SslConfig.class, includeNonSingletons, allowEagerInit);
}
@Override
public Object getObject() {
return get();
}
}
2.2、ReferenceConfig#get() 入口
可以看到在初始化的时候,最终会调用到get()方法,此方法是继承自ReferenceConfig的方法:
public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
public synchronized T get() {
if (destroyed) {
throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!");
}
//是否有引用
if (ref == null) {
// init 方法主要用于处理配置,以及调用 createProxy 生成代理类
init();
}
return ref;
}
}
2.3、ReferenceConfig#init()初始化
public synchronized void init() {
//只初始化一次
if (initialized) {
return;
}
if (bootstrap == null) {
bootstrap = DubboBootstrap.getInstance();
//获取所有的注册中心
if (null != this.getRegistries()) {
bootstrap.registries(this.getRegistries());
}
//全局配置初始化
bootstrap.initialize();
}
//校验和更新配置
checkAndUpdateSubConfigs();
//本地存根校验
checkStubAndLocal(interfaceClass);
//mock校验
ConfigValidationUtils.checkMock(interfaceClass, this);
// 添加 side、协议版本信息、时间戳和进程号等信息到 map 中
Map<String, String> map = new HashMap<String, String>();
map.put(SIDE_KEY, CONSUMER_SIDE);
ReferenceConfigBase.appendRuntimeParameters(map);
//非泛化服务的调用
if (!ProtocolUtils.isGeneric(generic)) {
String revision = Version.getVersion(interfaceClass, version);
if (revision != null && revision.length() > 0) {
map.put(REVISION_KEY, revision);
}
String[] methods = methods(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)), COMMA_SEPARATOR));
}
}
map.put(INTERFACE_KEY, interfaceName);
// 将 ApplicationConfig、ConsumerConfig、ReferenceConfig 等对象的字段信息添加到 map 中
AbstractConfig.appendParameters(map, getMetrics());
AbstractConfig.appendParameters(map, getApplication());
AbstractConfig.appendParameters(map, getModule());
// remove 'default.' prefix for configs from ConsumerConfig
// appendParameters(map, consumer, Constants.DEFAULT_KEY);
AbstractConfig.appendParameters(map, consumer);
AbstractConfig.appendParameters(map, this);
MetadataReportConfig metadataReportConfig = getMetadataReportConfig();
if (metadataReportConfig != null && metadataReportConfig.isValid()) {
map.putIfAbsent(METADATA_KEY, REMOTE_METADATA_STORAGE_TYPE);
}
Map<String, AsyncMethodInfo> attributes = null;
if (CollectionUtils.isNotEmpty(getMethods())) {
attributes = new HashMap<>();
for (MethodConfig methodConfig : getMethods()) {
AbstractConfig.appendParameters(map, methodConfig, methodConfig.getName());
String retryKey = methodConfig.getName() + ".retry";
// 检测 map 是否包含 methodName.retry
if (map.containsKey(retryKey)) {
String retryValue = map.remove(retryKey);
if ("false".equals(retryValue)) {
//设置失败重试次数
map.put(methodConfig.getName() + ".retries", "0");
}
}
// 添加 MethodConfig 中的“属性”字段到 attributes
// 比如 onreturn、onthrow、oninvoke 等
AsyncMethodInfo asyncMethodInfo = AbstractConfig.convertMethodConfig2AsyncInfo(methodConfig);
if (asyncMethodInfo != null) {
// consumerModel.getMethodModel(methodConfig.getName()).addAttribute(ASYNC_KEY, asyncMethodInfo);
attributes.put(methodConfig.getName(), asyncMethodInfo);
}
}
}
// 获取服务消费者 ip 地址
String hostToRegistry = ConfigUtils.getSystemProperty(DUBBO_IP_TO_REGISTRY);
if (StringUtils.isEmpty(hostToRegistry)) {
hostToRegistry = NetUtils.getLocalHost();
} else if (isInvalidLocalHost(hostToRegistry)) {
throw new IllegalArgumentException(
"Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
}
map.put(REGISTER_IP_KEY, hostToRegistry);
//所有参数放入attachment缓存中,到时候会发送到远程端
serviceMetadata.getAttachments().putAll(map);
// proxy层创建代理类
ref = createProxy(map);
serviceMetadata.setTarget(ref);
serviceMetadata.addAttribute(PROXY_CLASS_REF, ref);
// 根据服务名,ReferenceConfig,代理类构建 ConsumerModel
ConsumerModel consumerModel = repository.lookupReferredService(serviceMetadata.getServiceKey());
consumerModel.setProxyObject(ref);
consumerModel.init(attributes);
initialized = true;
//校验引用的服务是否可用
checkInvokerAvailable();
// 发送服务引用事件
dispatch(new ReferenceConfigInitializedEvent(this, invoker));
}
public void checkAndUpdateSubConfigs() {
if (StringUtils.isEmpty(interfaceName)) {
throw new IllegalStateException("<dubbo:reference interface=\"\" /> interface not allow null!");
}
// 使用显示配置的module、application 来进行一些全局配置
completeCompoundConfigs(consumer);
// 获取消费者的全局配置
checkDefault();
// SPI获取ConfigInitializer对应的实现类或者通过url获取configInitializer://配置并执行响应的配置初始化操作
List<ConfigInitializer> configInitializers = ExtensionLoader.getExtensionLoader(ConfigInitializer.class)
.getActivateExtension(URL.valueOf("configInitializer://"), (String[]) null);
configInitializers.forEach(e -> e.initReferConfig(this));
//将Environment变量注入到当前对象的配置中
this.refresh();
if (getGeneric() == null && getConsumer() != null) {
// 设置 generic
setGeneric(getConsumer().getGeneric());
}
//泛化调用的处理
if (ProtocolUtils.isGeneric(generic)) {
interfaceClass = GenericService.class;
} else {
try {
//反射获取调用接口
interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
.getContextClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
//解析调用方法
checkInterfaceAndMethods(interfaceClass, getMethods());
}
//舒适化service元数据
initServiceMetadata(consumer);
serviceMetadata.setServiceType(getActualInterface());
// TODO, uncomment this line once service key is unified
serviceMetadata.setServiceKey(URL.buildKey(interfaceName, group, version));
//获取服务仓库
ServiceRepository repository = ApplicationModel.getServiceRepository();
//获取接口的描述
ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass);
//对应的服务注册消费者
repository.registerConsumer(
serviceMetadata.getServiceKey(),
serviceDescriptor,
this,
null,
serviceMetadata);
resolveFile();
ConfigValidationUtils.validateReferenceConfig(this);
postProcessConfig();
}
2.4、reference代理proxy类的创建
createProxy首先是根据配置检查是否为本地调用,本地调用是通过 InjvmProtocol 的 refer 方法生成 InjvmInvoker 实例。非本地钓鱼功能需要读取直连配置项,或注册中心 url,并将读取到的 url 存储到 urls 中。然后根据 urls 元素数量进行后续操作。若只有一个url直接通过 Protocol 自适应拓展类构建 Invoker 实例接口。如果是多个注册中心或服务直连 url,此时先根据 url 构建 Invoker。然后再通过 Cluster 合并多个 Invoker,最后调用 ProxyFactory 生成代理类。
/**
* reference代理类的创建
* @param map
* @return
*/
@SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
private T createProxy(Map<String, String> map) {
// 本地引用
if (shouldJvmRefer(map)) {
// 生成本地引用 URL,协议为 injvm
URL url = new URL(LOCAL_PROTOCOL, LOCALHOST_VALUE, 0, interfaceClass.getName()).addParameters(map);
// 调用 refer 方法构建 InjvmInvoker 实例
invoker = REF_PROTOCOL.refer(interfaceClass, url);
if (logger.isInfoEnabled()) {
logger.info("Using injvm service " + interfaceClass.getName());
}
// 远程引用
} else {
urls.clear();
// url 不为空,表明用户可能想进行点对点调用
if (url != null && url.length() > 0) {
//多个url的话需要切分
String[] us = SEMICOLON_SPLIT_PATTERN.split(url);
if (us != null && us.length > 0) {
for (String u : us) {
URL url = URL.valueOf(u);
if (StringUtils.isEmpty(url.getPath())) {
// 设置接口全限定名为 url 路径
url = url.setPath(interfaceName);
}
// 检测 url 协议是否为 registry,若是,表明用户想使用指定的注册中心
if (UrlUtils.isRegistry(url)) {
// 将 map 转换为查询字符串,并作为 refer 参数的值添加到 url 中
urls.add(url.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
} else {
// 合并 url,移除服务提供者的一些配置(这些配置来源于用户配置的 url 属性),
// 比如线程池相关配置。并保留服务提供者的部分配置,比如版本,group,时间戳等
// 最后将合并后的配置设置为 url 查询字符串中。
urls.add(ClusterUtils.mergeUrl(url, map));
}
}
}
} else { // assemble URL from register center's configuration
// if protocols not injvm checkRegistry
//通过注册中心调用的方式
if (!LOCAL_PROTOCOL.equalsIgnoreCase(getProtocol())) {
//检查配置中心
checkRegistry();
List<URL> us = ConfigValidationUtils.loadRegistries(this, false);
if (CollectionUtils.isNotEmpty(us)) {
for (URL u : us) {
URL monitorUrl = ConfigValidationUtils.loadMonitor(this, u);
if (monitorUrl != null) {
//填充监控地址
map.put(MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
}
// 注册中心地址添加 refer 服务消费元数据
urls.add(u.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
}
}
if (urls.isEmpty()) {
throw new IllegalStateException(
"No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() +
" use dubbo version " + Version.getVersion() +
", please config <dubbo:registry address=\"...\" /> to your spring config.");
}
}
}
if (urls.size() == 1) {
//创建远程invoker
invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0));
} else {
//多个注册中心需要创建多个invoker
List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
URL registryURL = null;
for (URL url : urls) {
Invoker<?> referInvoker = REF_PROTOCOL.refer(interfaceClass, url);
//验证invoker的可用性
if (shouldCheck()) {
if (referInvoker.isAvailable()) {
invokers.add(referInvoker);
} else {
referInvoker.destroy();
}
} else {
invokers.add(referInvoker);
}
// 会覆盖前遍历的注册中心,使用最后一条注册中心数据
if (UrlUtils.isRegistry(url)) {
registryURL = url; // use last registry url
}
}
if (shouldCheck() && invokers.size() == 0) {
throw new IllegalStateException("Failed to check the status of the service "
+ interfaceName
+ ". No provider available for the service "
+ (group == null ? "" : group + "/")
+ interfaceName +
(version == null ? "" : ":" + version)
+ " from the multi registry cluster"
+ " use dubbo version " + Version.getVersion());
}
if (registryURL != null) {
// 默认使用 zone-aware 集群容错策略 来处理多个订阅 zone-aware=org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareCluster
//zone-aware的应用在多注册中心的场景。
//业务部署假设是双注册中心:
//则对应消费端,先在注册中心间选择,再到选定的注册中心选址:
String cluster = registryURL.getParameter(CLUSTER_KEY, ZoneAwareCluster.NAME);
// 合并invoker ZoneAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker(RegistryDirectory, routing happens here) -> Invoker
invoker = Cluster.getCluster(cluster, false).join(new StaticDirectory(registryURL, invokers));
} else {
// 直连的处理方式
String cluster = CollectionUtils.isNotEmpty(invokers)
?
(invokers.get(0).getUrl() != null ? invokers.get(0).getUrl().getParameter(CLUSTER_KEY, ZoneAwareCluster.NAME) :
Cluster.DEFAULT)
: Cluster.DEFAULT;
//Directory 即服务目录, 服务目录中存储了一些和服务提供者有关的信息,通过服务目录,服务消费者可获取到服务提供者的信息,比如 ip、端口、服务协议等。通过这些信息,服务消费者就可通过 Netty 等客户端进行远程调用。
//StaticDirectory 即静态服务目录,顾名思义,它内部存放的 Invoker 是不会变动的。
invoker = Cluster.getCluster(cluster).join(new StaticDirectory(invokers));
}
}
}
if (logger.isInfoEnabled()) {
logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl());
}
//服务元数据保存到本地
URL consumerURL = new URL(CONSUMER_PROTOCOL, map.remove(REGISTER_IP_KEY), 0, map.get(INTERFACE_KEY), map);
MetadataUtils.publishServiceDefinition(consumerURL);
// 通过invoker创建代理(javassist)
return (T) PROXY_FACTORY.getProxy(invoker, ProtocolUtils.isGeneric(generic));
}
上述代码涉及到了StaticDirectory。这在dubbo中成为服务目录。服务目录中存储了一些和服务提供者有关的信息,通过服务目录,服务消费者可获取到服务提供者的信息,比如 ip、端口、服务协议等。通过这些信息,服务消费者就可通过 Netty 等客户端进行远程调用。在一个服务集群中,服务提供者数量并不是一成不变的,如果集群中新增了一台机器,相应地在服务目录中就要新增一条服务提供者记录。或者,如果服务提供者的配置修改了,服务目录中的记录也要做相应的更新。
实际上服务目录在获取注册中心的服务配置信息后,会为每条配置信息生成一个 Invoker 对象,并把这个 Invoker 对象存储起来,这个 Invoker 才是服务目录最终持有的对象。
服务目录目前内置的实现有两个,分别为 StaticDirectory 和 RegistryDirectory,它们均是 AbstractDirectory 的子类
StaticDirectory 即静态服务目录,顾名思义,它内部存放的 Invoker 是不会变动的。
RegistryDirectory 是一种动态服务目录,实现了 NotifyListener 接口。当注册中心服务配置发生变化后,RegistryDirectory 可收到与当前服务相关的变化。收到变更通知后,RegistryDirectory 可根据配置变更信息刷新 Invoker 列表。RegistryDirectory 中有几个比较重要的逻辑,第一是 Invoker 的列举逻辑,第二是接收服务配置变更的逻辑,第三是 Invoker 列表的刷新逻辑。接下来按顺序对这三块逻辑进行分析。
下面分析服务引用的过程:
服务引用有两种,一种是本地服务引用,一种是远程服务引用。
本地服务引用的判断:
protected boolean shouldJvmRefer(Map<String, String> map) {
URL tmpUrl = new URL("temp", "localhost", 0, map);
boolean isJvmRefer;
if (isInjvm() == null) {
//如果有指定url则不做本地引用
if (url != null && url.length() > 0) {
isJvmRefer = false;
} else {
// 根据 url 的协议、scope 以及 injvm 等参数检测是否需要本地引用
// 比如如果用户显式配置了 scope=local,此时 isInjvmRefer 返回 true
isJvmRefer = InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl);
}
} else {
isJvmRefer = isInjvm();
}
return isJvmRefer;
}
2.5、refer创建invoker
2.5.1、RegistryProtocol的refer创建invoker
RegistryProtocol#refer主要做了以下操作:
1. 获取注册中心协议类型,并获取注册中心实例。
2. 获取group 配置,根据 group 决定 doRefer 方法的 Cluster 参数。多分组情况下是 MergeableCluster,默认情况下是 FailoverCluster。
3. doRefer 方法创建一个 RegistryDirectory 实例,交由RegistryDirectory 建立路由链路、订阅节点、容错机制的包装,最终获取到服务节点的一个Invoker
@Override
@SuppressWarnings("unchecked")
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
//获取注册中心地址
url = getRegistryUrl(url);
//注册中心实例
Registry registry = getRegistry(url);
if (RegistryService.class.equals(type)) {
return proxyFactory.getInvoker((T) registry, type, url);
}
// 解析url中的参数到map中
Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded(REFER_KEY));
//group组的解析
String group = qs.get(GROUP_KEY);
if (group != null && group.length() > 0) {
if ((COMMA_SPLIT_PATTERN.split(group)).length > 1 || "*".equals(group)) {
// 如果是多分组的情况下,通过 SPI 加载 MergeableCluster 实例,并调用 doRefer 继续执行服务引用逻辑。
return doRefer(Cluster.getCluster(MergeableCluster.NAME), registry, type, url, qs);
}
}
//集群容错
Cluster cluster = Cluster.getCluster(qs.get(CLUSTER_KEY));
return doRefer(cluster, registry, type, url, qs);
}
proxyFactory#getInvoker会调用到JavassistProxyFactory的getInvoker方法:
public class JavassistProxyFactory extends AbstractProxyFactory {
@Override
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
// 为目标类创建 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);
}
};
}
}
oRefer 方法创建一个 RegistryDirectory 实例,然后生成服务者消费者链接,并向注册中心进行注册。注册完毕后,紧接着订阅 providers、configurators、routers 等节点下的数据。完成订阅后,RegistryDirectory 会收到这几个节点下的子节点信息。由于一个服务可能部署在多台服务器上,这样就会在 providers 产生多个节点,这个时候就需要 Cluster 将多个服务节点合并为一个,并生成一个 Invoker。
public class RegistryProtocol implements Protocol {
protected <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url, Map<String, String> parameters) {
URL consumerUrl = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters);
ClusterInvoker<T> migrationInvoker = getMigrationInvoker(this, cluster, registry, type, url, consumerUrl);
//invoker的拦截器链
return interceptInvoker(migrationInvoker, url, consumerUrl);
}
protected <T> Invoker<T> interceptInvoker(ClusterInvoker<T> invoker, URL url, URL consumerUrl) {
//获取所有与注册协议相关的监听器
List<RegistryProtocolListener> listeners = findRegistryProtocolListeners(url);
if (CollectionUtils.isEmpty(listeners)) {
return invoker;
}
//监听器与invoker之间的绑定
for (RegistryProtocolListener listener : listeners) {
//该方法最终会执行到RegistryProtocol的doCreateInvoker()方法
listener.onRefer(this, invoker, consumerUrl);
}
return invoker;
}
protected <T> ClusterInvoker<T> doCreateInvoker(DynamicDirectory<T> directory, Cluster cluster, Registry registry, Class<T> type) {
//目录设置注册中心和协议
directory.setRegistry(registry);
directory.setProtocol(protocol);
// all attributes of REFER_KEY
Map<String, String> parameters = new HashMap<String, String>(directory.getConsumerUrl().getParameters());
// 消费者的链接
URL urlToRegistry = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters);
//是否需要注册
if (directory.isShouldRegister()) {
directory.setRegisteredConsumerUrl(urlToRegistry);
//消费者的注册过程,注册到注册中心
registry.register(directory.getRegisteredConsumerUrl());
}
//调用链
directory.buildRouterChain(urlToRegistry);
//订阅当前的服务提供者
directory.subscribe(toSubscribeUrl(urlToRegistry));
// 一个注册中心可能有多个服务提供者,因此这里需要将多个服务提供者合并为一个
return (ClusterInvoker<T>) cluster.join(directory);
}
}
2.5.2、DubboProtocol的refer创建invoker
dubbo协议的refer主要使用过AbstractProtocol的refer来进行调用的
public abstract class AbstractProtocol implements Protocol {
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
return new AsyncToSyncInvoker<>(protocolBindingRefer(type, url));
}
}
ExchangeClient#getClients方法用获取了客户端实例,它的底层是NettyClient,Dubbo 会通过 NettyClient 来进行通信:
public class DubboProtocol extends AbstractProtocol {
public <T> Invoker<T> protocolBindingRefer(Class<T> serviceType, URL url) throws RpcException {
optimizeSerialization(url);
// 创建dubbo rpc invoker.
DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
invokers.add(invoker);
return invoker;
}
private ExchangeClient[] getClients(URL url) {
// 获取连接数默认是0 未配置
int connections = url.getParameter(CONNECTIONS_KEY, 0);
if (connections == 0) {
/*
* The xml configuration should have a higher priority than properties.
*/
String shareConnectionsStr = url.getParameter(SHARE_CONNECTIONS_KEY, (String) null);
connections = Integer.parseInt(StringUtils.isBlank(shareConnectionsStr) ? ConfigUtils.getProperty(SHARE_CONNECTIONS_KEY,
DEFAULT_SHARE_CONNECTIONS) : shareConnectionsStr);
// 获取共享客户端
return getSharedClient(url, connections).toArray(new ExchangeClient[0]);
} else {
ExchangeClient[] clients = new ExchangeClient[connections];
for (int i = 0; i < clients.length; i++) {
//初始化共享客户端
clients[i] = initClient(url);
}
return clients;
}
}
private ExchangeClient initClient(URL url) {
// 客户端类型,默认netty
String str = url.getParameter(CLIENT_KEY, url.getParameter(SERVER_KEY, DEFAULT_REMOTING_CLIENT));
// 添加编解码和心跳包参数到 url 中
url = url.addParameter(CODEC_KEY, DubboCodec.NAME);
url = url.addParameterIfAbsent(HEARTBEAT_KEY, String.valueOf(DEFAULT_HEARTBEAT));
// BIO 是不允许的,因为它有严重的性能问题。
if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) {
throw new RpcException("Unsupported client type: " + str + "," +
" supported client type is " +
StringUtils.join(ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions(), " "));
}
ExchangeClient client;
try {
// 获取 lazy 配置,并根据配置值决定创建的客户端类型
if (url.getParameter(LAZY_CONNECT_KEY, false)) {
// 带懒加载的ExchangeClient 实例
client = new LazyConnectExchangeClient(url, requestHandler);
} else {
// ExchangeClient 实例
client = Exchangers.connect(url, requestHandler);
}
} catch (RemotingException e) {
throw new RpcException("Fail to create remoting client for service(" + url + "): " + e.getMessage(), e);
}
return client;
}
}
Exchangers#getExchanger 会通过 SPI 加载 HeaderExchangeClient 实例
public class Exchangers {
public static ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
if (url == null) {
throw new IllegalArgumentException("url == null");
}
if (handler == null) {
throw new IllegalArgumentException("handler == null");
}
// 获取 Exchanger 实例,默认为 HeaderExchangeClient
return getExchanger(url).connect(url, handler);
}
public static Exchanger getExchanger(URL url) {
String type = url.getParameter(Constants.EXCHANGER_KEY, Constants.DEFAULT_EXCHANGER);
return getExchanger(type);
}
public static Exchanger getExchanger(String type) {
//spi获取Exchanger的实例
return ExtensionLoader.getExtensionLoader(Exchanger.class).getExtension(type);
}
}
public class HeaderExchanger implements Exchanger {
public static final String NAME = "header";
@Override
public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
// 这里包含了多个调用,分别如下:
// 1. 创建 HeaderExchangeHandler 对象
// 2. 创建 DecodeHandler 对象
// 3. 通过 Transporters 构建 Client 实例
// 4. 创建 HeaderExchangeClient 对象
return new HeaderExchangeClient(Transporters.connect(url, new DecodeHandler(new HeaderExchangeHandler(handler))), true);
}
@Override
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
// 创建 HeaderExchangeServer 实例,该方法包含了多个逻辑,分别如下:
// 1. new HeaderExchangeHandler(handler)
// 2. new DecodeHandler(new HeaderExchangeHandler(handler))
// 3. Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler)))
return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}
}
getTransporter 方法返回的是自适应拓展类,该类会在运行时根据客户端类型加载指定的 Transporter 实现类。若用户未配置客户端类型,则默认加载 NettyTransporter,并调用该类的 connect 方法。如下:
public class Transporters {
public static Client connect(URL url, ChannelHandler... handlers) throws RemotingException {
if (url == null) {
throw new IllegalArgumentException("url == null");
}
ChannelHandler handler;
if (handlers == null || handlers.length == 0) {
handler = new ChannelHandlerAdapter();
} else if (handlers.length == 1) {
handler = handlers[0];
} else {
// 如果 handler 数量大于1,则创建一个 ChannelHandler 分发器
handler = new ChannelHandlerDispatcher(handlers);
}
// 获取 Transporter 自适应拓展类,并调用 connect 方法生成 Client 实例
return getTransporter().connect(url, handler);
}
public static Transporter getTransporter() {
return ExtensionLoader.getExtensionLoader(Transporter.class).getAdaptiveExtension();
}
}
最后就是底层的NettyTransporter:
public class NettyTransporter implements Transporter {
public static final String NAME = "netty3";
@Override
public RemotingServer bind(URL url, ChannelHandler handler) throws RemotingException {
// 创建 NettyServer
return new NettyServer(url, handler);
}
@Override
public Client connect(URL url, ChannelHandler handler) throws RemotingException {
// 创建 NettyClient 对象
return new NettyClient(url, handler);
}
}
2.6、代理类的创建
上接2.4的代码,Invoker 创建完毕后,需要为服务接口生成代理对象。远程调用是通过代理对象处理的,代理对象生成的入口方法为是ProxyFactory 的 getProxy,默认实现类是JavassistProxyFactory:
public class JavassistProxyFactory extends AbstractProxyFactory {
@Override
@SuppressWarnings("unchecked")
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
// 生成 Proxy 子类(Proxy 是抽象类)。并调用 Proxy 子类的 newInstance 方法创建 Proxy 实例
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
}
Proxy#getProxy:
public abstract class Proxy {
public static Proxy getProxy(Class<?>... ics) {
return getProxy(ClassUtils.getClassLoader(Proxy.class), ics);
}
public static Proxy getProxy(ClassLoader cl, Class<?>... ics) {
if (ics.length > MAX_PROXY_COUNT) {
throw new IllegalArgumentException("interface limit exceeded");
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < ics.length; i++) {
String itf = ics[i].getName();
// 判断是否为借口
if (!ics[i].isInterface()) {
throw new RuntimeException(itf + " is not a interface.");
}
Class<?> tmp = null;
try {
//反射获取
tmp = Class.forName(itf, false, cl);
} catch (ClassNotFoundException e) {
}
// 检测接口是否相同,这里 tmp 有可能为空
if (tmp != ics[i]) {
throw new IllegalArgumentException(ics[i] + " is not visible from class loader");
}
// 用;拼接全限定名
sb.append(itf).append(';');
}
// 使用拼接后的全限定名名作为 key
String key = sb.toString();
// get cache by class loader.
final Map<String, Object> cache;
// cache class
final Map<String, Object> classCache;
synchronized (PROXY_CACHE_MAP) {
cache = PROXY_CACHE_MAP.computeIfAbsent(cl, k -> new HashMap<>());
classCache = PROXY_CLASS_MAP.computeIfAbsent(cl, k -> new HashMap<>());
}
Proxy proxy = null;
synchronized (cache) {
do {
// 从缓存中获取 Reference<Proxy> 实例
Object value = cache.get(key);
if (value instanceof Reference<?>) {
proxy = (Proxy) ((Reference<?>) value).get();
if (proxy != null) {
return proxy;
}
}
// get Class by key.
Object clazzObj = classCache.get(key);
if (null == clazzObj || clazzObj instanceof Reference<?>) {
Class<?> clazz = null;
if (clazzObj instanceof Reference<?>) {
clazz = (Class<?>) ((Reference<?>) clazzObj).get();
}
// 并发控制,保证只有一个线程可以进行后续操作
if (null == clazz) {
if (value == PENDING_GENERATION_MARKER) {
try {
cache.wait();
} catch (InterruptedException e) {
}
} else {
// 放置标志位到缓存中,并跳出 while 循环进行后续操作
cache.put(key, PENDING_GENERATION_MARKER);
break;
}
} else {
try {
proxy = (Proxy) clazz.newInstance();
return proxy;
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
} finally {
if (null == proxy) {
cache.remove(key);
} else {
cache.put(key, new SoftReference<Proxy>(proxy));
}
}
}
}
}
while (true);
}
long id = PROXY_CLASS_COUNTER.getAndIncrement();
String pkg = null;
ClassGenerator ccp = null, ccm = null;
try {
ccp = ClassGenerator.newInstance(cl);
Set<String> worked = new HashSet<>();
List<Method> methods = new ArrayList<>();
for (int i = 0; i < ics.length; i++) {
// 检测接口访问级别是否为非public
if (!Modifier.isPublic(ics[i].getModifiers())) {
// 获取接口包名
String npkg = ics[i].getPackage().getName();
if (pkg == null) {
pkg = npkg;
} else {
if (!pkg.equals(npkg)) {
throw new IllegalArgumentException("non-public interfaces from different packages");
}
}
}
// 添加接口到 ClassGenerator 中
ccp.addInterface(ics[i]);
for (Method method : ics[i].getMethods()) {
//方法描述
String desc = ReflectUtils.getDesc(method);
// 如果方法描述字符串已在 worked 中,则忽略。考虑这种情况,
// A 接口和 B 接口中包含一个完全相同的方法
if (worked.contains(desc) || Modifier.isStatic(method.getModifiers())) {
continue;
}
worked.add(desc);
int ix = methods.size();
//返回值类型
Class<?> rt = method.getReturnType();
//参数类型
Class<?>[] pts = method.getParameterTypes();
//Object[] args = new Object[N]
StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
for (int j = 0; j < pts.length; j++) {
//args[N] = ($w)$N;
code.append(" args[").append(j).append("] = ($w)$").append(j + 1).append(";");
}
// 生成 InvokerHandler 接口的 invoker 方法调用语句:
// Object ret = handler.invoke(this, methods[N], args);
code.append(" Object ret = handler.invoke(this, methods[").append(ix).append("], args);");
if (!Void.TYPE.equals(rt)) {
//非void return (java.lang.String) ret;
code.append(" return ").append(asArgument(rt, "ret")).append(";");
}
methods.add(method);
// 添加方法名、访问控制符、参数列表、方法代码等信息到 ClassGenerator 中
ccp.addMethod(method.getName(), method.getModifiers(), rt, pts, method.getExceptionTypes(), code.toString());
}
}
if (pkg == null) {
pkg = PACKAGE_NAME;
}
// 接口代理类名称:pkg + ".proxy" + id
String pcn = pkg + ".proxy" + id;
ccp.setClassName(pcn);
ccp.addField("public static java.lang.reflect.Method[] methods;");
// private java.lang.reflect.InvocationHandler handler
ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
// 为接口代理类添加带有 InvocationHandler 参数的构造方法,比如:
// porxy0(java.lang.reflect.InvocationHandler arg0) {
// handler=$1;
// }
ccp.addConstructor(Modifier.PUBLIC, new Class<?>[] {InvocationHandler.class}, new Class<?>[0], "handler=$1;");
// 为接口代理类添加默认构造方法
ccp.addDefaultConstructor();
//创建代理类
Class<?> clazz = ccp.toClass();
clazz.getField("methods").set(null, methods.toArray(new Method[0]));
// 代理子类名称
String fcn = Proxy.class.getName() + id;
ccm = ClassGenerator.newInstance(cl);
//设置类名
ccm.setClassName(fcn);
//默认构造器
ccm.addDefaultConstructor();
//父类
ccm.setSuperClass(Proxy.class);
// 为 Proxy 的抽象方法 newInstance 生成实现代码,形如:
// public Object newInstance(java.lang.reflect.InvocationHandler h) {
// return new org.apache.dubbo.proxy0($1);
// }
ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
//生成实现类
Class<?> pc = ccm.toClass();
//通过反射创建代理类
proxy = (Proxy) pc.newInstance();
synchronized (classCache) {
classCache.put(key, new SoftReference<Class<?>>(pc));
}
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
} finally {
// release ClassGenerator
if (ccp != null) {
ccp.release();
}
if (ccm != null) {
ccm.release();
}
synchronized (cache) {
if (proxy == null) {
cache.remove(key);
} else {
//缓存代理类 软应用
cache.put(key, new SoftReference<>(proxy));
}
cache.notifyAll();
}
}
return proxy;
//ccp 用于为服务接口生成代理类,比如我们有一个 DemoService 接口,这个接口代理类就是由 ccp 生成的。ccm 则是用于为 org.apache.dubbo.common.bytecode.Proxy 抽象类生成子类,主要是实现 Proxy 类的抽象方法。
}
}
三、总结:
服务引用的入口在ReferenceBean类下的getObject方法中,通过RegistryProtocol.refer()方法实现数据的拉取、订阅和服务Invoker转换等操作。通过
协议类型会创建对应的注册中心实例,并根据容错策略cluster来合并Invoker。
对于合并的每一个Invoker,会通过监听器去进行具体的实现,如设置基本的服务路由链,进行当前服务的订阅等操作。最终合并到Cluster集群中然后返回。最终返回一个Invoker。