• Dubbo源码学习--服务是如何引用的


    相关文章:

    Dubbo源码学习文章目录

    ReferenceBean

    跟服务引用一样,Dubbo的reference配置会被转成ReferenceBean类,ReferenceBean实现了InitializingBean接口,直接看afterPropertiesSet()也就是spring为Bean提供的初始化方法

    方法调用顺序afterPropertiesSet() -> getObject() -> get() -> init() -> createProxy()

    afterPropertiesSet()

    afterPropertiesSet()作用为装载应用信息、注册、模块、监控等配置,然后调用getObject()

        public void afterPropertiesSet() throws Exception {
            //.....
            setApplication(applicationConfig);
            //.....
            setModule(moduleConfig);
            //.....
            super.setRegistries(registryConfigs);
            //.....
            Boolean b = isInit();
            if (b == null && getConsumer() != null) {
                b = getConsumer().isInit();
            }
            if (b != null && b.booleanValue()) {
                getObject();
            }
        }
    

    getObject()

    getObject() 返回 get() 执行结果

        public Object getObject() throws Exception {
            return get();
        }
    

    get()

    get() 如果接口代理类(ref) 为空则调用 init() 生成接口代理类

        public synchronized T get() {
            if (destroyed){
                throw new IllegalStateException("Already destroyed!");
            }
        	if (ref == null) {
        		init();
        	}
        	return ref;
        }
    

    init()

    init() 根据配置生成Map 然后调用 createProxy() 生成代理类

        ref = createProxy(map);
    

    createProxy()

    具体作用见注释

    	private T createProxy(Map<String, String> map) {
            //1. 创建临时Url
    		URL tmpUrl = new URL("temp", "localhost", 0, map);
    		final boolean isJvmRefer;
            // 省略部分代码.....
            //2.判断是否暴漏本地服务
    		if (isJvmRefer) {
    			URL url = new URL(Constants.LOCAL_PROTOCOL, NetUtils.LOCALHOST, 0, interfaceClass.getName()).addParameters(map);
    			invoker = refprotocol.refer(interfaceClass, url);
            // 省略部分代码.....
    		} else {
                //3.判断用户指定URL,指定的URL可能是对点对直连地址,也可能是注册中心URL
                if (url != null && url.length() > 0) { 
                    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 { 
                    //4. 通过注册中心配置拼装URL
                	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.");
                    }
                }
                // 5.调用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) {
                        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));
                    }
                }
            }
            // 省略.....
            // 6.创建服务代理
            return (T) proxyFactory.getProxy(invoker);
        }
    
    

    RegistryProtocol

    refprotocol.refer()

    refprotocol.refer() 先后经过修饰类 ProtocolFilterWrapper、ProtocolListenerWrapper 最后执行RegistryProtocol

    ProtocolFilterWrapper -> ProtocolListenerWrapper

        //ProtocolFilterWrapper
        public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
            if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
                return protocol.refer(type, url);
            }
            return buildInvokerChain(protocol.refer(type, url), Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER);
        }
        
        //ProtocolListenerWrapper
        public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
            if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
                return protocol.refer(type, url);
            }
            return new ListenerInvokerWrapper<T>(protocol.refer(type, url), 
                    Collections.unmodifiableList(
                            ExtensionLoader.getExtensionLoader(InvokerListener.class)
                            .getActivateExtension(url, Constants.INVOKER_LISTENER_KEY)));
        }
    

    RegistryProtocol

      @SuppressWarnings("unchecked")
    	public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
            // Constants.REGISTRY_KEY: registry 
            // Constants.DEFAULT_REGISTRY: dubbo
            url = url.setProtocol(url.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_REGISTRY)).removeParameter(Constants.REGISTRY_KEY);
            Registry registry = registryFactory.getRegistry(url);
            if (RegistryService.class.equals(type)) {
            	return proxyFactory.getInvoker((T) registry, type, url);
            }
            // 配置Group信息
            // group="a,b" or group="*"
            Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded(Constants.REFER_KEY)); // Constants.REFER_KEY:refer
            String group = qs.get(Constants.GROUP_KEY);
            if (group != null && group.length() > 0 ) {
                if ( ( Constants.COMMA_SPLIT_PATTERN.split( group ) ).length > 1
                        || "*".equals( group ) ) {
                    return doRefer( getMergeableCluster(), registry, type, url );
                }
            }
            return doRefer(cluster, registry, type, url);
        }
    

    doRefer()

    1. 调用FailbackRegistry.register() 在注册中心注册消费者subscribeUrl
    2. 调用FailbackRegistry.subscribe() 订阅注册中心subscribeUrl
    
        private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
            RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url);
            directory.setRegistry(registry);
            directory.setProtocol(protocol);
            // Constants.CONSUMER_PROTOCOL: consumer
            URL subscribeUrl = new URL(Constants.CONSUMER_PROTOCOL, NetUtils.getLocalHost(), 0, type.getName(), directory.getUrl().getParameters());
            
            //consumer://10.9.22.12/com.**.ShopService?application=test&check=false&dubbo=2.8.4
            //&interface=com.**.ShopService&methods=getList&pid=6168&retries=1&revision=1.0-SNAPSHOT
            //&side=consumer&timeout=6000&timestamp=1484275807134&version=1.0
            if (! Constants.ANY_VALUE.equals(url.getServiceInterface())
                    && url.getParameter(Constants.REGISTER_KEY, true)) {
                registry.register(subscribeUrl.addParameters(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY,
                        Constants.CHECK_KEY, String.valueOf(false)));
            }
            directory.subscribe(subscribeUrl.addParameter(Constants.CATEGORY_KEY, 
                    Constants.PROVIDERS_CATEGORY 
                    + "," + Constants.CONFIGURATORS_CATEGORY 
                    + "," + Constants.ROUTERS_CATEGORY));
            return cluster.join(directory);
        }
    

    引用服务时序

  • 相关阅读:
    python---RabbitMQ(1)简单队列使用,消息依次分发(一对一),消息持久化处理
    python---ORM之SQLAlchemy(4)relationship多对多练习
    ShowcaseView-master
    HT518V311
    上方显示进度的进度条
    ArrowDrawable
    一个仿 github for windows 及 windows 8 的进度条
    高仿语音发送动画,按住闪烁,滑动跟随,删除翻转丢入垃圾桶,比较全的一个动画实例
    Ledongli
    RotatingDoughnut
  • 原文地址:https://www.cnblogs.com/javanoob/p/dubbo_reference.html
Copyright © 2020-2023  润新知