五Dubbo服务引用源码分析--2创建远程调用的代理-2.1ReferenceBean.getObject

五Dubbo服务引用源码分析--2创建远程调用的代理-2.1ReferenceBean.getObject

5.1 创建远程调用的代理--getBean(DemoService.class)->getObject

在5.0消费端启动部分,已经分析了代理对象创建的时机:

image-20221227114246765

getBean(DemoService.class)然后调用ReferenceBean.getObject方法,完成代理对象初始化

ReferenceBean
  @Override
    public Object getObject() throws Exception {
        return get();
    }
ReferenceConfig
    public synchronized T get() {
        if (destroyed) {
            throw new IllegalStateException("Already destroyed!");
        }
        if (ref == null) {
            init();
        }
        return ref;
    }

TAG0 ReferenceConfig.init()

ReferenceConfig
private void init() {
        if (initialized) {
            return;
        }
        initialized = true;
        if (interfaceName == null || interfaceName.length() == 0) {
            throw new IllegalStateException("<dubbo:reference interface=\"\" /> interface not allow null!");
        }

  			//设置consumer的全局配置:如果consumerConfig为null,创建consumerConfig,并appendProperties(consumer)
        checkDefault();
        appendProperties(this); //完善传入的config内的setter属性
        if (getGeneric() == null && getConsumer() != null) {
            setGeneric(getConsumer().getGeneric());
        }
        if (ProtocolUtils.isGeneric(getGeneric())) {
            interfaceClass = GenericService.class;
        } else {
            try {
              //获取接口的类
                interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
                        .getContextClassLoader());
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            checkInterfaceAndMethods(interfaceClass, methods);//检查methods是否在对应的接口中
        }
  /** …………………………………………………………………………………………resolveFile文件的创建、管理……………………………………………………………………………………………………………………*/
        String resolve = System.getProperty(interfaceName);
        String resolveFile = null;
        if (resolve == null || resolve.length() == 0) {
            resolveFile = System.getProperty("dubbo.resolve.file");
            if (resolveFile == null || resolveFile.length() == 0) {
                File userResolveFile = new File(new File(System.getProperty("user.home")), "dubbo-resolve.properties");
                if (userResolveFile.exists()) {
                    resolveFile = userResolveFile.getAbsolutePath();
                }
            }
            if (resolveFile != null && resolveFile.length() > 0) {
                Properties properties = new Properties();
                FileInputStream fis = null;
                try {
                    fis = new FileInputStream(new File(resolveFile));
                    properties.load(fis);
                } catch (IOException e) {
                    throw new IllegalStateException("Unload " + resolveFile + ", cause: " + e.getMessage(), e);
                } finally {
                    try {
                        if (null != fis) fis.close();
                    } catch (IOException e) {
                        logger.warn(e.getMessage(), e);
                    }
                }
                resolve = properties.getProperty(interfaceName);
            }
        }
        if (resolve != null && resolve.length() > 0) {
            url = resolve;
            if (logger.isWarnEnabled()) {
                if (resolveFile != null) {
                    logger.warn("Using default dubbo resolve file " + resolveFile + " replace " + interfaceName + "" + resolve + " to p2p invoke remote service.");
                } else {
                    logger.warn("Using -D" + interfaceName + "=" + resolve + " to p2p invoke remote service.");
                }
            }
        }
  //准备consumer端的主要配置类
        if (consumer != null) {
            if (application == null) { //applicationContext,是referenceBean中awareXX注入的属性
                application = consumer.getApplication();
            }
            if (module == null) {
                module = consumer.getModule();
            }
            if (registries == null) {
                registries = consumer.getRegistries();
            }
            if (monitor == null) {
                monitor = consumer.getMonitor();
            }
        }
        if (module != null) {
            if (registries == null) {
                registries = module.getRegistries();
            }
            if (monitor == null) {
                monitor = module.getMonitor();
            }
        }
        if (application != null) {
            if (registries == null) {
                registries = application.getRegistries();
            }
            if (monitor == null) {
                monitor = application.getMonitor();
            }
        }
        checkApplication();
//????????
        checkStubAndMock(interfaceClass);
  
/**………………………………………………………………………………………………………………检查配置,构建map………………………………………………………………………………………………………………………………………………… */
        Map<String, String> map = new HashMap<String, String>();
        Map<Object, Object> attributes = new HashMap<Object, Object>();
        map.put(Constants.SIDE_KEY, Constants.CONSUMER_SIDE);
        map.put(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion());
        map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
        if (ConfigUtils.getPid() > 0) {
            map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
        }
        if (!isGeneric()) {
            String revision = Version.getVersion(interfaceClass, version);
            if (revision != null && revision.length() > 0) {
                map.put("revision", revision);
            }

            String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
            if (methods.length == 0) {
                logger.warn("NO method found in service interface " + interfaceClass.getName());
                map.put("methods", Constants.ANY_VALUE);
            } else {
                map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
            }
        }
        map.put(Constants.INTERFACE_KEY, interfaceName); //将调用服务的接口名,放入map中
        appendParameters(map, application);
        appendParameters(map, module);
        appendParameters(map, consumer, Constants.DEFAULT_KEY);
        appendParameters(map, this);
        String prefix = StringUtils.getServiceKey(map);
        if (methods != null && !methods.isEmpty()) {
            for (MethodConfig method : methods) {
                appendParameters(map, method, method.getName());
                String retryKey = method.getName() + ".retry";
                if (map.containsKey(retryKey)) {
                    String retryValue = map.remove(retryKey);
                    if ("false".equals(retryValue)) {
                        map.put(method.getName() + ".retries", "0");
                    }
                }
                appendAttributes(attributes, method, prefix + "." + method.getName());
                checkAndConvertImplicitConfig(method, map, attributes);
            }
        }
//获取注册到registry的consumer端ip
        String hostToRegistry = ConfigUtils.getSystemProperty(Constants.DUBBO_IP_TO_REGISTRY);
        if (hostToRegistry == null || hostToRegistry.length() == 0) {
          //192.168.0.101
            hostToRegistry = NetUtils.getLocalHost();
        } else if (isInvalidLocalHost(hostToRegistry)) {
            throw new IllegalArgumentException("Specified invalid registry ip from property:" + Constants.DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
        }
        map.put(Constants.REGISTER_IP_KEY, hostToRegistry);

        //attributes are stored by system context.
        StaticContext.getSystemContext().putAll(attributes);
//TAG1 createProxy(map)
        ref = createProxy(map);
        ConsumerModel consumerModel = new ConsumerModel(getUniqueServiceName(), this, ref, interfaceClass.getMethods());
        ApplicationModel.initConsumerModel(getUniqueServiceName(), consumerModel);
    }

在init()方法中,是检查配置并将信息装配到map中,包括method、interface、register.ip等配置

image-20221227142455610

TAG1 createProxy(map)

ReferenceConfig
 private T createProxy(Map<String, String> map) {
/**…………………………………………………………………………………………………………………判断是否是本地引用……………………………………………………………………………………………………………………………… */
  //创建临时url--temp://localhost?application=demotest-consumer&dubbo=2.0.2&interface=com.alibaba.dubbo.demo.DemoService&methods=getPermissions&organization=dubbox&owner=programmer&pid=92731&qos.enable=false&register.ip=192.168.0.101&side=consumer&timestamp=1672116260245
        URL tmpUrl = new URL("temp", "localhost", 0, map);
        final boolean isJvmRefer;
  			//目前,是根据url中scope=local,判断引用服务是在jvm中
        if (isInjvm() == null) {//1 
          //url是referenceConfig内属性,如果初始化时指定,就不再执行本地引用,只远程调用
            if (url != null && url.length() > 0) { //2
                isJvmRefer = false;
            } else if (InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl)) {  //从map参数中看scope=local,为true
                // by default, reference local service if there is
                isJvmRefer = true;
            } else {
                isJvmRefer = false;
            } //2
        } else {
            isJvmRefer = isInjvm().booleanValue();
        } //1 

/**………………………………………………………………本地引用……………………………………………………………………………………暂时略过 */
        if (isJvmRefer) {
            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 { //0
    /** …………………………………………………………………………………………直连…………………………………………………………………………………………………………*/
    			//如果referenceConfig中初始化的url不为空(根据该初始化URL,直接引用---不需要配置中心,直连服务provider)
            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 (url.getPath() == null || url.getPath().length() == 0) {
                            url = url.setPath(interfaceName);//设置服务引用的path
                        }
                        if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
                            urls.add(url.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));
                        } else {
                          //将referenceConfig中构造的map,合并到直连的url的参数对上去,然后添加到urls的list上
                            urls.add(ClusterUtils.mergeUrl(url, map));
                        }
                    }
                }
            } 
  /**………………………………………………………… 从注册中心的configuration配置中,组装的服务端providerURL地址 ……………………………………………………………………*/
    else { //1
//TAG1.1 loadRegistries(false)  加载注册中心url地址
      //registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demotest-consumer&dubbo=2.0.2&organization=dubbox&owner=programmer&pid=92731&qos.enable=false&registry=zookeeper&timestamp=1672207675233
                List<URL> us = loadRegistries(false);
                if (us != null && !us.isEmpty()) { //2 
                    for (URL u : us) {
                        URL monitorUrl = loadMonitor(u);
                        if (monitorUrl != null) {
                            map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
                        }
                      //向注册中心中添加refer:encoded(map参数)的parameter,然后添加入List<url> urls中
                      //registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demotest-consumer&dubbo=2.0.2&organization=dubbox&owner=programmer&pid=92731&qos.enable=false&refer=application%3Ddemotest-consumer%26dubbo%3D2.0.2%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DgetPermissions%26organization%3Ddubbox%26owner%3Dprogrammer%26pid%3D92731%26qos.enable%3Dfalse%26register.ip%3D192.168.0.101%26side%3Dconsumer%26timestamp%3D1672116260245&registry=zookeeper&timestamp=1672207675233
                        urls.add(u.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));
                    }
                } //2 
                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.");
                }
            }//1
    
    
						//注册中心只有一个
            if (urls.size() == 1) {
//TAG1.2 refprotocol.refer(interfaceClass, urls.get(0))
                invoker = refprotocol.refer(interfaceClass, urls.get(0));
            } 
    //注册中心多个(会refer多个invokers,然后需要cluster.join为一个)
    				else { //1 
                List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
                URL registryURL = null;
                for (URL url : urls) { //2 
                  //注册中心多个时,需要从每个注册中心中,protocol.refer构造invoker,并添加入invokers列表
                    invokers.add(refprotocol.refer(interfaceClass, url));
                    if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
                        registryURL = url; // 使用最后一个注册中心地址
                    }
                } //2 
                if (registryURL != null) { // 2 URLs中有注册中心
                    // use AvailableCluster only when register's cluster is available
                    URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME);
//TAG1.3 cluster.join(new StaticDirectory(u, invokers))
                    invoker = cluster.join(new StaticDirectory(u, invokers));
                } else { // 如果URLs中,没有注册中心url
                    invoker = cluster.join(new StaticDirectory(invokers));
                } //2 
            } //1
    
        }//0

        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());
        }
//TAG1.4 proxyFactory.getProxy(invoker)
        // create service proxy
        return (T) proxyFactory.getProxy(invoker);
    }

首先,ReferenceConfig内的属性:

public class ReferenceConfig<T> extends AbstractReferenceConfig {
		//服务引用的protocol协议(protocol$Adaptive)
    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; //端对端调用的URL
    // method configs
    private List<MethodConfig> methods;
    // default config
    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;

createProxy(Map<String, String> map)逻辑如下:

1 根据传入的map,构造临时tmpurl;
2 从tmpurl中的scope,判断是否是本地引用isJvmRefer;
3.1 本地引用--略
3.2 远程引用
	3.2.1 如果referenceConfig.url不为null,就是直连服务(直接给定provider端的url,可能是服务,可能是registryUrl);
	3.2.2 如果referenceConfig.url为null:
			step1:TAG1.1 loadRegistries(false) 获取注册中心地址;
			step2:遍历注册中心地址,然后加入refer:encode(map),然后urls.add();
			step3:判断urls.length==1
					step3.1 是:TAG1.2 refprotocol.refer(interfaceClass, urls.get(0)) 构造invoker
					step3.2 否(即为loadRegistry获取多个地址):
							step3.2.1 判断urls中,是否有注册中心,即urls中是否有registry://的protocol协议头
									1 有注册中心:TAG1.3 cluster.join(new StaticDirectory(u, invokers));
									2 没有注册中心:cluster.join(new StaticDirectory(invokers))
									区别上述两个方法

TAG1.1 loadRegistries(false)

AbstractInterfaceConfig
 protected List<URL> loadRegistries(boolean provider) {
  			//如果有注册中心registryConfig,将referenceconfig内配置信息,追加到registry注册中心中
        checkRegistry(); 
        List<URL> registryList = new ArrayList<URL>();
  			//consumer.xml中配置的注册中心registryConfig
        if (registries != null && !registries.isEmpty()) {
            for (RegistryConfig config : registries) {
                String address = config.getAddress(); //zookeeper://127.0.0.1:2181
                if (address == null || address.length() == 0) {
                    address = Constants.ANYHOST_VALUE;
                }
                String sysaddress = System.getProperty("dubbo.registry.address"); //null
                if (sysaddress != null && sysaddress.length() > 0) {
                    address = sysaddress;
                }
                if (address.length() > 0 && !RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
                  //构造注册中心url的map参数对
                    Map<String, String> map = new HashMap<String, String>();
                    appendParameters(map, application);
                    appendParameters(map, config);
                    map.put("path", RegistryService.class.getName()); //注册中心的path为RegistryService类路径
                    map.put("dubbo", Version.getProtocolVersion());
                    map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
                    if (ConfigUtils.getPid() > 0) {
                        map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
                    }
                    if (!map.containsKey("protocol")) {
                        if (ExtensionLoader.getExtensionLoader(RegistryFactory.class).hasExtension("remote")) {
                            map.put("protocol", "remote");
                        } else {
                            map.put("protocol", "dubbo"); //registry的protocol默认为dubbo
                        }
                    }
                  //根据address和map,解析并构造注册中心URL
                  //zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demotest-consumer&dubbo=2.0.2&organization=dubbox&owner=programmer&pid=92731&qos.enable=false&timestamp=1672207675233
                    List<URL> urls = UrlUtils.parseURLs(address, map);
                    for (URL url : urls) {
                      //添加registry=zookeeper
                        url = url.addParameter(Constants.REGISTRY_KEY, url.getProtocol());
                      //设置注册中心url地址的协议头为registry://
          //registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demotest-consumer&dubbo=2.0.2&organization=dubbox&owner=programmer&pid=92731&qos.enable=false&registry=zookeeper&timestamp=1672207675233
                        url = url.setProtocol(Constants.REGISTRY_PROTOCOL);
                      //provider=false,表示不是provider端,是consumer端
                        if ((provider && url.getParameter(Constants.REGISTER_KEY, true))
                                || (!provider && url.getParameter(Constants.SUBSCRIBE_KEY, true))) {
                            registryList.add(url);
                        }
                    }
                }
            }
        }
        return registryList;
    }

主要逻辑是,根据注册中心的address+map,构造registryURL=registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demotest-consumer&dubbo=2.0.2&organization=dubbox&owner=programmer&pid=92731&qos.enable=false&registry=zookeeper&timestamp=1672207675233。

协议头为registry://,表示一个注册中心的服务。

TAG1.2 refprotocol.refer(interfaceClass, urls.get(0))--REFER

调用protocol.refer,生成核心的invoker对象。

image-20221228142545151

public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol {

  public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        com.alibaba.dubbo.common.URL url = arg1;
    		//registry
        String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
        if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
    //获取Protocol.class的扩展类名为registry的protocol
        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
//REFER
        return extension.refer(arg0, arg1);
    }

由于Protocol在dubbo中有wrapper机制、filter过滤等,因此获取的registryProtocol外层包裹了ProtocolFilterWrapper、ProtocolListenerWrapper

image-20221228145051199

image-20221228145322540

posted @ 2023-03-13 14:45  LeasonXue  阅读(41)  评论(0)    收藏  举报