消费端的代码解析是从下面这段代码开始的
注解的方式的初始化入口是
ReferenceConfifig.get
public synchronized T get() {
checkAndUpdateSubConfigs(); //检查和修改配置
if (destroyed) {
throw new IllegalStateException("The invoker of ReferenceConfig(" +
url + ") has already destroyed!");
}
ReferenceAnnotationBeanPostProcessor->ReferenceBeanInvocationHandler.init-
>ReferenceConfig.get() 获得一个远程代理类init
初始化的过程,和服务发布的过程类似,会有特别多的判断以及参数的组装. 我们只需要关注
createProxy,创建代理类的方法。
if (ref == null) { //如果当前接口的远程代理引用为空,则进行初始化
init();
}
return ref;
}
private void init() {
//省略...
ref = createProxy(map);
//省略...
}
createProxy
代码比较长,但是逻辑相对比较清晰
1. 判断是否为本地调用,如果是则使用injvm协议进行调用
2. 判断是否为点对点调用,如果是则把url保存到urls集合中,如果url为1,进入步骤4,如果urls>1
,则执行5
3. 如果是配置了注册中心,遍历注册中心,把url添加到urls集合,url为1,进入步骤4,如果urls>1
,则执行5
4. 直连构建invoker
5. 构建invokers集合,通过cluster合并多个invoker
6. 最后调用 ProxyFactory 生成代理类
private T createProxy(Map<String, String> map) {
if (shouldJvmRefer(map)) { //判断是否是在同一个jvm进程中调用
URL url = new URL(Constants.LOCAL_PROTOCOL,
Constants.LOCALHOST_VALUE, 0, interfaceClass.getName()).addParameters(map);
invoker = refprotocol.refer(interfaceClass, url);
if (logger.isInfoEnabled()) {
logger.info("Using injvm service " + interfaceClass.getName());
}
} else {
//url 如果不为空,说明是点对点通信
if (url != null && url.length() > 0) { // user specified URL, could
be peer-to-peer address, or register center's address.
String[] us = Constants.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.setPath(interfaceName);
}
// 检测 url 协议是否为 registry,若是,表明用户想使用指定的注册
中心
if
(Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
// 将 map 转换为查询字符串,并作为 refer 参数的值添加到
url 中
urls.add(url.addParameterAndEncoded(Constants.REFER_KEY,
StringUtils.toQueryString(map)));
} else {
// 合并 url,移除服务提供者的一些配置(这些配置来源于用户配置
的 url 属性),
// 比如线程池相关配置。并保留服务提供者的部分配置,比如版本,
group,时间戳等
// 最后将合并后的配置设置为 url 查询字符串中。
urls.add(ClusterUtils.mergeUrl(url, map));
}
}
}
} else { // assemble URL from register center's configuration
checkRegistry(); //校验注册中心的配置以及是否有必要从配置中心组装url
//这里的代码实现和服务端类似,也是根据注册中心配置进行解析得到URL
//这里的URL肯定也是:
registry://ip:port/org.apache.dubbo.service.RegsitryService
List<URL> us = loadRegistries(false);
if (CollectionUtils.isNotEmpty(us)) {
for (URL u : us) {
URL monitorUrl = loadMonitor(u);
if (monitorUrl != null) {
map.put(Constants.MONITOR_KEY,
URL.encode(monitorUrl.toFullString()));
}
urls.add(u.addParameterAndEncoded(Constants.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
address=\"...\" /> to your spring config.");
}
}
//如果值配置了一个注册中心或者一个服务提供者,直接使用refprotocol.refer
if (urls.size() == 1) {
invoker = refprotocol.refer(interfaceClass, urls.get(0));
} else {
List<Invoker>> invokers = new ArrayList<Invoker>>();
URL registryURL = null;
for (URL url : urls) {//遍历urls生成多个invoker
invokers.add(refprotocol.refer(interfaceClass, url));protocol.refer
这里通过指定的协议来调用refer生成一个invoker对象,invoker前面讲过,它是一个代理对象。那么在
当前的消费端而言,invoker主要用于执行远程调用。
这个protocol,又是一个自适应扩展点,它得到的是一个Protocol$Adaptive.
if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
registryURL = url; // use last registry url
}
}
if (registryURL != null) { //如果registryUrl不为空,构建静态
directory
// 使用RegistryAwareCluster
URL u = registryURL.addParameter(Constants.CLUSTER_KEY,
RegistryAwareCluster.NAME);
// 通过Cluster将多个invoker合并
RegistryAwareClusterInvoker(StaticDirectory) ->
FailoverClusterInvoker(RegistryDirectory, will execute route) -> Invoker
invoker = cluster.join(new StaticDirectory(u, invokers));
} else {
invoker = cluster.join(new StaticDirectory(invokers));
}
}
}
//检查invoker的有效性
if (shouldCheck() && !invoker.isAvailable()) {
// make it possible for consumer to retry later if provider is
temporarily unavailable
initialized = false;
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 url " + invoker.getUrl() + " to the consumer " +
NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion());
}
if (logger.isInfoEnabled()) {
logger.info("Refer dubbo service " + interfaceClass.getName() + "
from url " + invoker.getUrl());
}
/**
* @since 2.7.0
* ServiceData Store
*/
MetadataReportService metadataReportService = null;
if ((metadataReportService = getMetadataReportService()) != null) {
URL consumerURL = new URL(Constants.CONSUMER_PROTOCOL,
map.remove(Constants.REGISTER_IP_KEY), 0, map.get(Constants.INTERFACE_KEY),
map);
metadataReportService.publishConsumer(consumerURL);
}
// create service proxy
return (T) proxyFactory.getProxy(invoker);
}