1. 程式人生 > >Dubbo源碼閱讀筆記2

Dubbo源碼閱讀筆記2

except temp setpath available ttr blog time param provider

### 消費方初始化

消費方初始化的入口在ReferenceConfig類的get方法
前面基本和服務方的初始化一致

public class ReferenceConfig<T> extends AbstractReferenceConfig {

    private static final long serialVersionUID = -5864351140409987595L;

    private static final Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

    private static final Cluster cluster = ExtensionLoader.getExtensionLoader(Cluster.class).getAdaptiveExtension();

    private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
    private final List<URL> urls = new ArrayList<URL>();
    // 接口類型
    private String interfaceName;
    private Class<?> interfaceClass;
    // 客戶端類型
    private String client;
    // 點對點直連服務提供地址
    private String url;
    // 方法配置
    private List<MethodConfig> methods;
    // 缺省配置
    private ConsumerConfig consumer;
    private String protocol;
    // 接口代理類引用
    private transient volatile T ref;
    // 接口調用器
    private transient volatile Invoker<?> invoker;
    // 是否已初始化
    private transient volatile boolean initialized;
    // 是否已銷毀
    private transient volatile boolean destroyed;
    
    // ...
}

public synchronized T get() {
    if (destroyed) {
        throw new IllegalStateException("Already destroyed!");
    }
    
    // 實現類引用不存在時初始化
    if (ref == null) {
        init();
    }
    return ref;
}

private void init() {
    // ...
    // 處理各種配置,放進map中
    
    //attributes通過系統context進行存儲.
    StaticContext.getSystemContext().putAll(attributes);
    
    // 生成代理(重點方法)
    ref = createProxy(map);
    
    // 將實現者和配置信息封裝成model
    ConsumerModel consumerModel = new ConsumerModel(getUniqueServiceName(), this, ref, interfaceClass.getMethods());
    // 放進全局context中
    ApplicationModel.initConsumerModele(getUniqueServiceName(), consumerModel);
}

創建代理類,代理遠程方法實現

private T createProxy(Map<String, String> map) {
    // 判斷是否要引用本地服務
    URL tmpUrl = new URL("temp", "localhost", 0, map);
    final boolean isJvmRefer;
    if (isInjvm() == null) {
        if (url != null && url.length() > 0) { //指定URL的情況下,不做本地引用
            isJvmRefer = false;
        } else if (InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl)) {
            //默認情況下如果本地有服務暴露,則引用本地服務.
            isJvmRefer = true;
        } else {
            isJvmRefer = false;
        }
    } else {
        isJvmRefer = isInjvm().booleanValue();
    }

    if (isJvmRefer) {
        // 跟服務端的exportLocal對應
        URL url = new URL(Constants.LOCAL_PROTOCOL, NetUtils.LOCALHOST, 0, interfaceClass.getName()).addParameters(map);
        // 生成調用器,調用遠程方法實現
        invoker = refprotocol.refer(interfaceClass, url);
        if (logger.isInfoEnabled()) {
            logger.info("Using injvm service " + interfaceClass.getName());
        }
    } else {
        if (url != null && url.length() > 0) { // 用戶指定URL,指定的URL可能是對點對直連地址,也可能是註冊中心URL
            String[] us = Constants.SEMICOLON_SPLIT_PATTERN.split(url);
            if (us != null && us.length > 0) {
                for (String u : us) {
                    URL url = URL.valueOf(u);
                    if (url.getPath() == null || url.getPath().length() == 0) {
                        url = url.setPath(interfaceName);
                    }
                    if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
                        urls.add(url.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));
                    } else {
                        urls.add(ClusterUtils.mergeUrl(url, map));
                    }
                }
            }
        } else { 
            // 通過註冊中心配置拼裝URL
            // 如:registry://127.0.0.1:6379/com.alibaba.dubbo.registry.RegistryService?application=demo-consumer&dubbo=2.0.0&file=${user.home}/.dubbo/dubbo-consumer.cache&owner=denis.huang&pid=15940&registry=redis&subscribe=true&timestamp=1513651178925
            List<URL> us = loadRegistries(false);
            if (us != null && us.size() > 0) {
                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 == null || urls.size() == 0) {
                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 = refprotocol.refer(interfaceClass, urls.get(0));
        } else {
            List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
            URL registryURL = null;
            for (URL url : urls) {
                invokers.add(refprotocol.refer(interfaceClass, url));
                if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
                    registryURL = url; // 用了最後一個registry url
                }
            }
            if (registryURL != null) { // 有 註冊中心協議的URL
                // 對有註冊中心的Cluster 只用 AvailableCluster
                URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME);
                invoker = cluster.join(new StaticDirectory(u, invokers));
            } else { // 不是 註冊中心的URL
                invoker = cluster.join(new StaticDirectory(invokers));
            }
        }
    }

    Boolean c = check;
    if (c == null && consumer != null) {
        c = consumer.isCheck();
    }
    if (c == null) {
        c = true; // default true
    }
    if (c && !invoker.isAvailable()) {
        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());
    }
    // 創建服務代理
    return (T) proxyFactory.getProxy(invoker);
}

Dubbo源碼閱讀筆記2