dubbo 动态调用分析

ApplicationConfig application = new ApplicationConfig();
//下面设置ApplicationConfig的配置,省略
ReferenceConfig ref = new ReferenceConfig();
ref.setApplication(application);
RegistryConfig reg = new RegistryConfig;//单节点模式
ref.setRegistries(reg);
if(async){
            ref.setAsync(async); // 设置异步调用
            async = false;
        }
ref.setInterface(interfaceName); // 设置接口名
ref.setGeneric(true); // 泛化
MethodConfig methodConfig = new MethodConfig(); // 方法配置
methodConfig.setName(method);
List methodList = new ArrayList();
methodList.add(methodConfig);
ref.setMethods(methodList);
ReferenceConfigCache cache = ReferenceConfigCache.getCache();
GenericService genericService = cache.get(ref);

 

上面代码不是可编译的,是为了表达基本的处理步骤而拼在一起的。

ReferenceConfigCache

调用ReferenceConfigCache.getCache()->getCache("_DEFAULT_")->getCache("_DEFAULT_",DEFAULT_KEY_GENERATOR)

DEFAULT_KEY_GENERATOR是一个内部静态类,正如它的类名所暗示的,它的主要作用就是根据ReferenceConfig生成一个key值串,由方法generateKey来实现。

最后返回的串结构为:group/interface:version。

public static final KeyGenerator DEFAULT_KEY_GENERATOR = new KeyGenerator() {
        public String generateKey(ReferenceConfig referenceConfig) {
            String iName = referenceConfig.getInterface();//interface name
            if(StringUtils.isBlank(iName)) {
                Class clazz = referenceConfig.getInterfaceClass();
                iName = clazz.getName();
            }
            if(StringUtils.isBlank(iName)) {
                throw new IllegalArgumentException("No interface info in ReferenceConfig" + referenceConfig);
            }

            StringBuilder ret = new StringBuilder();
            if(! StringUtils.isBlank(referenceConfig.getGroup())) {
                ret.append(referenceConfig.getGroup()).append("/");
            }
            ret.append(iName);
            if(! StringUtils.isBlank(referenceConfig.getVersion())) {
                ret.append(":").append(referenceConfig.getVersion());
            }
            return ret.toString();//"group/iName:version"
        }
    };


再转向getCache(name,keygenerator)

public static ReferenceConfigCache getCache(String name, KeyGenerator keyGenerator) {
        ReferenceConfigCache cache = cacheHolder.get(name);
        if(cache != null) {
            return cache;
        }
        cacheHolder.putIfAbsent(name, new ReferenceConfigCache(name, keyGenerator));
        return cacheHolder.get(name);
    

 

其中cacheHolder是一个concurrentHashMap,所以get的操作在多线程下是高效安全的。ReferenceConfigCache是一个用于缓存ReferenceConfig的工具类,只所以需要缓存是因为ReferenceConfig封装了与注册中心的连接和服务提供方的连接,如果不缓存是存在效率和内存使用问题。

@SuppressWarnings("unchecked")
	public  T get(ReferenceConfig referenceConfig) {
        String key = generator.generateKey(referenceConfig);

        ReferenceConfig config = cache.get(key);
        if(config != null) {
            return (T) config.get();
        }
        cache.putIfAbsent(key, referenceConfig);
        config = cache.get(key);
        return (T) config.get();
    }

 

首先根据生成的key(默认是group/interface:version)找到缓存的ReferenceConfig,然后会调用ReferenceConfig.get方法。


 

ReferenceConfig

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


这里的ref是接口代理类的引用,对于一个ReferenceConfig来说,第一次调用时ref是null的,所以会调用init方法,另外这个方法用synchronized修饰,所以是可以并发访问的,但也会成为并发调用时的瓶颈。

 private void init() {
    	//避免重复初始化
	    if (initialized) {
	        return;
	    }
	    //检查接口名称是否为空
    	if (interfaceName == null || interfaceName.length() == 0) {
    	    throw new IllegalStateException(" interface not allow null!");
    	}
    	// 获取消费者全局配置
    	checkDefault();
        appendProperties(this);
        //
        if (getGeneric() == null && getConsumer() != null) {
            setGeneric(getConsumer().getGeneric());//利用ConsumerConfig配置泛型
        }
        //如果是泛型接口,那么interfaceClass的类型是GenericService
        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);
        }
        String resolve = System.getProperty(interfaceName);
        String resolveFile = null;
        //如果服务比较多,可以指定dubbo-resolve.properties文件配置service(service集中配置文件)
        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 && resolveFile.length() > 0) {
        			logger.warn("Using default hsf resolve file " + resolveFile + " replace " + interfaceName + "" + resolve + " to p2p invoke remote service.");
        		} else {
        			logger.warn("Using -D" + interfaceName + "=" + resolve + " to p2p invoke remote service.");
        		}
    		}
        }
        //如果application module registries monitor未配置则使用consumer的
        if (consumer != null) {
            if (application == null) {
                application = consumer.getApplication();
            }
            if (module == null) {
                module = consumer.getModule();
            }
            if (registries == null) {
                registries = consumer.getRegistries();
            }
            if (monitor == null) {
                monitor = consumer.getMonitor();
            }
        }
        //如果module已关联,则关联module的regisries和monitor
        if (module != null) {
            if (registries == null) {
                registries = module.getRegistries();
            }
            if (monitor == null) {
                monitor = module.getMonitor();
            }
        }
        //如果application已关联,则关联application的registries和monitor
        if (application != null) {
            if (registries == null) {
                registries = application.getRegistries();
            }
            if (monitor == null) {
                monitor = application.getMonitor();
            }
        }
        checkApplication();
        //检查远端和本地服务接口真实存在(是否可load)
        checkStubAndMock(interfaceClass);
        Map map = new HashMap();
        //配置dubbo的端属性(是consumer还是provider)、版本、创建时间、进程号
        Map attributes = new HashMap();
        map.put(Constants.SIDE_KEY, Constants.CONSUMER_SIDE);
        map.put(Constants.HSF_VERSION_KEY, Version.getVersion());
        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(Arrays.asList(methods)), ","));
            }
        } else {//泛型 
       	 List methodList = new ArrayList();
       	 if(methods != null && methods.size()>0){
           	 for (MethodConfig method : methods) {
           		 methodList.add(method.getName());
           	 }
           	 if(methodList != null && methodList.size()>0){
           		 map.put("methods", StringUtils.join(new HashSet(methodList), ","));
           	 }
       	 }
       }
        map.put(Constants.INTERFACE_KEY, interfaceName);
        //调用application moudle consumer的get方法将属性设置到map中
        appendParameters(map, application);
        appendParameters(map, module);
        appendParameters(map, consumer, Constants.DEFAULT_KEY);
        appendParameters(map, this);
        String prifix = StringUtils.getServiceKey(map);
        if (methods != null && methods.size() > 0) {
            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, prifix + "." + method.getName());
                checkAndConvertImplicitConfig(method, map, attributes);
            }
        }
        //attributes通过系统context进行存储.
        StaticContext.getSystemContext().putAll(attributes);
        //在map装载了application module consumer reference的所有属性后创建代理
        ref = createProxy(map);
    }


(1)通过volatile boolean initialized参数来避免同一个ReferenceConfig被重复初始化。

(2)检查接口名称是否为空,如果为空,抛出异常。

(3)获取ConsumerConfig的默认全局配置。

(4)如果ReferenceConfig没有配置泛型标志(这里我们是设置了),设置了ConsumerConfig的泛型标志

(5)如果是泛型调用,接口类设置为GenericService.class,否则正常设置 。

(6)在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连,

在JVM启动参数中加入-D参数映射服务地址,如key为服务名,value为服务提供者url。



java
 -Dcom.alibaba.xxx.XxxService=dubbo://localhost:20890

如果服务比较多,也可以用文件映射,如用-Ddubbo.resolve.file指定映射文件路径,如果不指定会自动加载${user.home}/dubbo-resolve.properties文件。(7)如果没有通过-D参数映射服务地址,也没有通过-D参数进行文件映射,尝试读取${user.home}/dubbo-resovle.properties文件。

(8)如果没有设置ApplicationConfig,尝试从ConsumerConfig中获取。如果没有设置ModuleConfig,尝试从ConsumerConfig中获取 。

(9)如果没有设置RegistryConfig,尝试从ConsumerConfig中获取,失败再尝试从ModuleConfig中获取,失败再尝试从ApplicationConfig中获取。

(10)如果没有设置MonitorConfig,尝试从ConsumerConfig中获取,失败再尝试从ModuleConfig中获取,失败再尝试从ApplicationConfig中获取。

(11)在装载了application module consumer reference的所有属性后创建代理。

 

最后欢迎大家访问我的个人网站:1024s

你可能感兴趣的:(秒扒Dubbo)