Dubbbo 记录源码疑问

 

dubbo 版本 2.5.3

1.JVM可以直接配置对应interface的url 或者指定dubbo路径文件,格式参照properties

ReferenceConfig.class line 185

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 && resolveFile.length() > 0) {
        			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.");
        		}
    		}
        }

2.这里是否走本地的相关判断没看懂

ReferenceConfig.class line 338

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) {
			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());
            }
		}
    public boolean isInjvmRefer(URL url) {
    	final boolean isJvmRefer;
    	String scope = url.getParameter(Constants.SCOPE_KEY);
    	//本身已经是jvm协议了,走正常流程就是了.
    	if (Constants.LOCAL_PROTOCOL.toString().equals(url.getProtocol())) {
    		isJvmRefer = false;
    	} else if (Constants.SCOPE_LOCAL.equals(scope) || (url.getParameter("injvm", false))) {
			//如果声明为本地引用
			//scope=local || injvm=true 等价 injvm标签未来废弃掉.
			isJvmRefer = true;
		} else if (Constants.SCOPE_REMOTE.equals(scope)){
			//声明了是远程引用,则不做本地引用
			isJvmRefer = false;
		} else if (url.getParameter(Constants.GENERIC_KEY, false)){
			//泛化调用不走本地
			isJvmRefer = false;
		} else if (getExporter(exporterMap, url) != null) {
			//默认情况下如果本地有服务暴露,则引用本地服务.
			isJvmRefer = true;
		} else {
			isJvmRefer = false;
		}
		return isJvmRefer;
    }

3.异步dubbo调用如何实现值传递有一块看不懂

FutureFilter.class line 123

后来看了这篇文章就清楚了一些 

https://blog.csdn.net/u013160932/article/details/81144471

    private void fireReturnCallback(final Invoker invoker, final Invocation invocation, final Object result) {
        final Method onReturnMethod = (Method)StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), Constants.ON_RETURN_METHOD_KEY));
        final Object onReturnInst = StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), Constants.ON_RETURN_INSTANCE_KEY));

        //not set onreturn callback
        if (onReturnMethod == null  &&  onReturnInst == null ){
            return ;
        }
        
        if (onReturnMethod == null  ||  onReturnInst == null ){
            throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() +" has a onreturn callback config , but no such "+(onReturnMethod == null ? "method" : "instance")+" found. url:"+invoker.getUrl());
        }
        if (onReturnMethod != null && ! onReturnMethod.isAccessible()) {
            onReturnMethod.setAccessible(true);
        }
        
        Object[] args = invocation.getArguments();
        Object[] params ;
        Class[] rParaTypes = onReturnMethod.getParameterTypes() ;
        if (rParaTypes.length >1 ) {
            if (rParaTypes.length == 2 && rParaTypes[1].isAssignableFrom(Object[].class)){
                params = new Object[2];
                params[0] = result;
                params[1] = args ;
            }else {
                params = new Object[args.length + 1];
                params[0] = result;
                System.arraycopy(args, 0, params, 1, args.length);
            }
        } else {
            params = new Object[] { result };
        }
        try {
            onReturnMethod.invoke(onReturnInst, params);
        } catch (InvocationTargetException e) {
            fireThrowCallback(invoker, invocation, e.getTargetException());
        } catch (Throwable e) {
            fireThrowCallback(invoker, invocation, e);
        }
    }

4. 一些因引用了外部包(包含自定义dubbo filter)可以使用url里面增加key的方式去掉对应的filter

类似: reference.filter=-xxx.XXXX

ProtocolFilterWrapper.class

    public  Invoker refer(Class type, URL url) throws RpcException {
        return "registry".equals(url.getProtocol())?this.protocol.refer(type, url):buildInvokerChain(this.protocol.refer(type, url), "reference.filter", "consumer");
    }

ExtensionLoader.class

    public List getActivateExtension(URL url, String key, String group) {
        String value = url.getParameter(key);
        return this.getActivateExtension(url, value != null && value.length() != 0?Constants.COMMA_SPLIT_PATTERN.split(value):null, group);
    }

    public List getActivateExtension(URL url, String[] values, String group) {
        List exts = new ArrayList();
        List names = values == null?new ArrayList(0):Arrays.asList(values);
        String name;
        if(!((List)names).contains("-default")) {
            this.getExtensionClasses();
            Iterator i$ = this.cachedActivates.entrySet().iterator();

            while(i$.hasNext()) {
                Entry entry = (Entry)i$.next();
                name = (String)entry.getKey();
                Activate activate = (Activate)entry.getValue();
                if(this.isMatchGroup(group, activate.group())) {
                    T ext = this.getExtension(name);
                    if(!((List)names).contains(name) && !((List)names).contains("-" + name) && this.isActive(activate, url)) {
                        exts.add(ext);
                    }
                }
            }

            Collections.sort(exts, ActivateComparator.COMPARATOR);
        }

        List usrs = new ArrayList();

        for(int i = 0; i < ((List)names).size(); ++i) {
            name = (String)((List)names).get(i);
            if(!name.startsWith("-") && !((List)names).contains("-" + name)) {
                if("default".equals(name)) {
                    if(usrs.size() > 0) {
                        exts.addAll(0, usrs);
                        usrs.clear();
                    }
                } else {
                    T ext = this.getExtension(name);
                    usrs.add(ext);
                }
            }
        }

        if(usrs.size() > 0) {
            exts.addAll(usrs);
        }

        return exts;
    }

6.dubbo整个架构活用SPI方式,如果需要手动添加filter 直接自定义对应的映射文件即可

对应的类继承Filter类即可

ExtensionLoader.class

public class ExtensionLoader {
    private static final Logger logger = LoggerFactory.getLogger(ExtensionLoader.class);
    private static final String SERVICES_DIRECTORY = "META-INF/services/";
    private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
    private static final String DUBBO_INTERNAL_DIRECTORY = "META-INF/dubbo/internal/";//重点
    private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
    private static final ConcurrentMap, ExtensionLoader> EXTENSION_LOADERS = new ConcurrentHashMap();
    private static final ConcurrentMap, Object> EXTENSION_INSTANCES = new ConcurrentHashMap();
    private final Class type;
    private final ExtensionFactory objectFactory;
    private final ConcurrentMap, String> cachedNames = new ConcurrentHashMap();
    private final Holder>> cachedClasses = new Holder();
    private final Map cachedActivates = new ConcurrentHashMap();
    private volatile Class cachedAdaptiveClass = null;
    private final ConcurrentMap> cachedInstances = new ConcurrentHashMap();
    private String cachedDefaultName;
    private final Holder cachedAdaptiveInstance = new Holder();
    private volatile Throwable createAdaptiveInstanceError;
    private Set> cachedWrapperClasses;
    private Map exceptions = new ConcurrentHashMap();
 
  

7.通过SPI方式,如果实现类的构造参数有传入当前接口的构造方法,则默认调用该构造参数进行实例化

ExtensionLoader.class line 498

    private T createExtension(String name) {
        Class clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw findException(name);
        }
        try {
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            injectExtension(instance);
            Set> wrapperClasses = cachedWrapperClasses;
            if (wrapperClasses != null && wrapperClasses.size() > 0) {
                for (Class wrapperClass : wrapperClasses) {
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
                    type + ")  could not be instantiated: " + t.getMessage(), t);
        }
    }

ExtensionLoader.class line 597

    private void loadFile(Map> extensionClasses, String dir) {
        String fileName = dir + type.getName();
        try {
            Enumeration urls;
            ClassLoader classLoader = findClassLoader();
            if (classLoader != null) {
                urls = classLoader.getResources(fileName);
            } else {
                urls = ClassLoader.getSystemResources(fileName);
            }
            if (urls != null) {
                while (urls.hasMoreElements()) {
                    java.net.URL url = urls.nextElement();
                    try {
                        BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));
                        try {
                            String line = null;
                            while ((line = reader.readLine()) != null) {
                                final int ci = line.indexOf('#');
                                if (ci >= 0) line = line.substring(0, ci);
                                line = line.trim();
                                if (line.length() > 0) {
                                    try {
                                        String name = null;
                                        int i = line.indexOf('=');
                                        if (i > 0) {
                                            name = line.substring(0, i).trim();
                                            line = line.substring(i + 1).trim();
                                        }
                                        if (line.length() > 0) {
                                            Class clazz = Class.forName(line, true, classLoader);
                                            if (! type.isAssignableFrom(clazz)) {
                                                throw new IllegalStateException("Error when load extension class(interface: " +
                                                        type + ", class line: " + clazz.getName() + "), class " 
                                                        + clazz.getName() + "is not subtype of interface.");
                                            }
                                            if (clazz.isAnnotationPresent(Adaptive.class)) {
                                                if(cachedAdaptiveClass == null) {
                                                    cachedAdaptiveClass = clazz;
                                                } else if (! cachedAdaptiveClass.equals(clazz)) {
                                                    throw new IllegalStateException("More than 1 adaptive class found: "
                                                            + cachedAdaptiveClass.getClass().getName()
                                                            + ", " + clazz.getClass().getName());
                                                }
                                            } else {
                                                try {
//这里是关键 如果有传入接口的构造参数则进入到wrapperClasses里面
                                                    clazz.getConstructor(type);
                                                    Set> wrappers = cachedWrapperClasses;
                                                    if (wrappers == null) {
                                                        cachedWrapperClasses = new ConcurrentHashSet>();
                                                        wrappers = cachedWrapperClasses;
                                                    }
                                                    wrappers.add(clazz);
                                                } catch (NoSuchMethodException e) {
                                                    clazz.getConstructor();
                                                    if (name == null || name.length() == 0) {
                                                        name = findAnnotationName(clazz);
                                                        if (name == null || name.length() == 0) {
                                                            if (clazz.getSimpleName().length() > type.getSimpleName().length()
                                                                    && clazz.getSimpleName().endsWith(type.getSimpleName())) {
                                                                name = clazz.getSimpleName().substring(0, clazz.getSimpleName().length() - type.getSimpleName().length()).toLowerCase();
                                                            } else {
                                                                throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + url);
                                                            }
                                                        }
                                                    }
                                                    String[] names = NAME_SEPARATOR.split(name);
                                                    if (names != null && names.length > 0) {
                                                        Activate activate = clazz.getAnnotation(Activate.class);
                                                        if (activate != null) {
                                                            cachedActivates.put(names[0], activate);
                                                        }
                                                        for (String n : names) {
                                                            if (! cachedNames.containsKey(clazz)) {
                                                                cachedNames.put(clazz, n);
                                                            }
                                                            Class c = extensionClasses.get(n);
                                                            if (c == null) {
                                                                extensionClasses.put(n, clazz);
                                                            } else if (c != clazz) {
                                                                throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    } catch (Throwable t) {
                                        IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + url + ", cause: " + t.getMessage(), t);
                                        exceptions.put(line, e);
                                    }
                                }
                            } // end of while read lines
                        } finally {
                            reader.close();
                        }
                    } catch (Throwable t) {
                        logger.error("Exception when load extension class(interface: " +
                                            type + ", class file: " + url + ") in " + url, t);
                    }
                } // end of while urls
            }
        } catch (Throwable t) {
            logger.error("Exception when load extension class(interface: " +
                    type + ", description file: " + fileName + ").", t);
        }
    }

 

8.创建SPI接口的实现类的时候,dubbo实现了类似spring自动注入的行为

这里dubbo保证所有SPI的接口,只有一个实例,多个类型的接口子类通过入参进行调用子类方法

ExtensionLoader line 498

    private T createExtension(String name) {
        Class clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw findException(name);
        }
        try {
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            //进行自动注入
            injectExtension(instance);
            Set> wrapperClasses = cachedWrapperClasses;
            if (wrapperClasses != null && wrapperClasses.size() > 0) {
                for (Class wrapperClass : wrapperClasses) {
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
                    type + ")  could not be instantiated: " + t.getMessage(), t);
        }
    }

ExtensionLoader line 523

    private T injectExtension(T instance) {
        try {
            if (objectFactory != null) {
                for (Method method : instance.getClass().getMethods()) {
                    if (method.getName().startsWith("set")
                            && method.getParameterTypes().length == 1
                            && Modifier.isPublic(method.getModifiers())) {
                        Class pt = method.getParameterTypes()[0];
                        try {
                            //根据setXXX的方法名截取bean的id进行注入
                            String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                            Object object = objectFactory.getExtension(pt, property);
                            if (object != null) {
                                method.invoke(instance, object);
                            }
                        } catch (Exception e) {
                            logger.error("fail to inject via method " + method.getName()
                                    + " of interface " + type.getName() + ": " + e.getMessage(), e);
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    }

9.ExtensionFactory如何初始化实例?

10.ExtensionLoader 懒加载SPI接口的代理类

    private String createAdaptiveExtensionClassCode() {
        StringBuilder codeBuidler = new StringBuilder();
        Method[] methods = type.getMethods();
        boolean hasAdaptiveAnnotation = false;
        for(Method m : methods) {
            if(m.isAnnotationPresent(Adaptive.class)) {
                hasAdaptiveAnnotation = true;
                break;
            }
        }
        // 完全没有Adaptive方法,则不需要生成Adaptive类
        if(! hasAdaptiveAnnotation)
            throw new IllegalStateException("No adaptive method on extension " + type.getName() + ", refuse to create the adaptive class!");
        
        codeBuidler.append("package " + type.getPackage().getName() + ";");
        codeBuidler.append("\nimport " + ExtensionLoader.class.getName() + ";");
        codeBuidler.append("\npublic class " + type.getSimpleName() + "$Adpative" + " implements " + type.getCanonicalName() + " {");
        
        for (Method method : methods) {
            Class rt = method.getReturnType();
            Class[] pts = method.getParameterTypes();
            Class[] ets = method.getExceptionTypes();

            Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
            StringBuilder code = new StringBuilder(512);
            if (adaptiveAnnotation == null) {
                code.append("throw new UnsupportedOperationException(\"method ")
                        .append(method.toString()).append(" of interface ")
                        .append(type.getName()).append(" is not adaptive method!\");");
            } else {
                int urlTypeIndex = -1;
                for (int i = 0; i < pts.length; ++i) {
                    if (pts[i].equals(URL.class)) {
                        urlTypeIndex = i;
                        break;
                    }
                }
                // 有类型为URL的参数
                if (urlTypeIndex != -1) {
                    // Null Point check
                    String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"url == null\");",
                                    urlTypeIndex);
                    code.append(s);
                    
                    s = String.format("\n%s url = arg%d;", URL.class.getName(), urlTypeIndex); 
                    code.append(s);
                }
                // 参数没有URL类型
                else {
                    String attribMethod = null;
                    
                    // 找到参数的URL属性
                    LBL_PTS:
                    for (int i = 0; i < pts.length; ++i) {
                        Method[] ms = pts[i].getMethods();
                        for (Method m : ms) {
                            String name = m.getName();
                            if ((name.startsWith("get") || name.length() > 3)
                                    && Modifier.isPublic(m.getModifiers())
                                    && !Modifier.isStatic(m.getModifiers())
                                    && m.getParameterTypes().length == 0
                                    && m.getReturnType() == URL.class) {
                                urlTypeIndex = i;
                                attribMethod = name;
                                break LBL_PTS;
                            }
                        }
                    }
                    if(attribMethod == null) {
                        throw new IllegalStateException("fail to create adative class for interface " + type.getName()
                        		+ ": not found url parameter or url attribute in parameters of method " + method.getName());
                    }
                    
                    // Null point check
                    String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"%s argument == null\");",
                                    urlTypeIndex, pts[urlTypeIndex].getName());
                    code.append(s);
                    s = String.format("\nif (arg%d.%s() == null) throw new IllegalArgumentException(\"%s argument %s() == null\");",
                                    urlTypeIndex, attribMethod, pts[urlTypeIndex].getName(), attribMethod);
                    code.append(s);

                    s = String.format("%s url = arg%d.%s();",URL.class.getName(), urlTypeIndex, attribMethod); 
                    code.append(s);
                }
                
                String[] value = adaptiveAnnotation.value();
                // 没有设置Key,则使用“扩展点接口名的点分隔 作为Key
                if(value.length == 0) {
                    char[] charArray = type.getSimpleName().toCharArray();
                    StringBuilder sb = new StringBuilder(128);
                    for (int i = 0; i < charArray.length; i++) {
                        if(Character.isUpperCase(charArray[i])) {
                            if(i != 0) {
                                sb.append(".");
                            }
                            sb.append(Character.toLowerCase(charArray[i]));
                        }
                        else {
                            sb.append(charArray[i]);
                        }
                    }
                    value = new String[] {sb.toString()};
                }
                
                boolean hasInvocation = false;
                for (int i = 0; i < pts.length; ++i) {
                    if (pts[i].getName().equals("com.alibaba.dubbo.rpc.Invocation")) {
                        // Null Point check
                        String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"invocation == null\");", i);
                        code.append(s);
                        s = String.format("\nString methodName = arg%d.getMethodName();", i); 
                        code.append(s);
                        hasInvocation = true;
                        break;
                    }
                }
                
                String defaultExtName = cachedDefaultName;
                String getNameCode = null;
                for (int i = value.length - 1; i >= 0; --i) {
                    if(i == value.length - 1) {
                        if(null != defaultExtName) {
                            if(!"protocol".equals(value[i]))
                                if (hasInvocation) 
                                    getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
                                else
                                    getNameCode = String.format("url.getParameter(\"%s\", \"%s\")", value[i], defaultExtName);
                            else
                                getNameCode = String.format("( url.getProtocol() == null ? \"%s\" : url.getProtocol() )", defaultExtName);
                        }
                        else {
                            if(!"protocol".equals(value[i]))
                                if (hasInvocation) 
                                    getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
                                else
                                    getNameCode = String.format("url.getParameter(\"%s\")", value[i]);
                            else
                                getNameCode = "url.getProtocol()";
                        }
                    }
                    else {
                        if(!"protocol".equals(value[i]))
                            if (hasInvocation) 
                                getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
                            else
                                getNameCode = String.format("url.getParameter(\"%s\", %s)", value[i], getNameCode);
                        else
                            getNameCode = String.format("url.getProtocol() == null ? (%s) : url.getProtocol()", getNameCode);
                    }
                }
                code.append("\nString extName = ").append(getNameCode).append(";");
                // check extName == null?
                String s = String.format("\nif(extName == null) " +
                		"throw new IllegalStateException(\"Fail to get extension(%s) name from url(\" + url.toString() + \") use keys(%s)\");",
                        type.getName(), Arrays.toString(value));
                code.append(s);
                
                s = String.format("\n%s extension = (% 0) {
                    codeBuidler.append(", ");
                }
                codeBuidler.append(pts[i].getCanonicalName());
                codeBuidler.append(" ");
                codeBuidler.append("arg" + i);
            }
            codeBuidler.append(")");
            if (ets.length > 0) {
                codeBuidler.append(" throws ");
                for (int i = 0; i < ets.length; i ++) {
                    if (i > 0) {
                        codeBuidler.append(", ");
                    }
                    codeBuidler.append(pts[i].getCanonicalName());
                }
            }
            codeBuidler.append(" {");
            codeBuidler.append(code.toString());
            codeBuidler.append("\n}");
        }
        codeBuidler.append("\n}");
        if (logger.isDebugEnabled()) {
            logger.debug(codeBuidler.toString());
        }
        return codeBuidler.toString();
    }

Dubbo的大致接口看了一下,发现所有接口的起始位置都在ExtensionLoader类里面。

所有的适配行为,都是根据Url的parameters来进行适配,而这个机制就是来自上面的代码

1.默认取SPI接口方法参数内的Url类型的对象

2.否则通过接口方法参数对象数组内某个对象包含get方法的返回值为Url的方法取到Url对象

3.接口名字为Protocol或者@Adaptive的key包含protocol的方法,通过Url的getProtocol获取extName(扩展类名 即SPI文件的key)

    1)如果不为Protocol或者@Adaptive的key包含protocol的话 且 接口参数不包含Invocation,则通过Url的getParamter进行获取extName

     2)否则通过Url的getMethodParameter获取extName

ps:getMethodParameter和getParameter的区别就是key是methodName+"."+key和直接用key查询的区别,如果methodName+"."+key没有在parameters里面的话最后还是会通getParameter进行获取

4.生成的源文件最终还是通过ExtensionLoader获取执行子类对象调用方法

所以整个Dubbo框架驱动都是通过Url对象,通过?cluster={customizedClusterKey}来适配SPI子类

 

11.Invoker的调用路径 Invoker.invoke->Directory.list -> Router.route -> LoanBalance.select

Invoke的调用模式有点装饰者模式的感觉 Invoke(StaticDirectory(Invoker(RegistryDirectory)))

RegistryDirectory的缓存的methodInvokerMap和urlInvokerMap 根据zookeeper的watch监听状态动态更新,保证每次调用都调用新的地址

 

12.MonitorFilter在调用完会收集相关信息

MonitorFilter line 59

    public Result invoke(Invoker invoker, Invocation invocation) throws RpcException {
        if (invoker.getUrl().hasParameter(Constants.MONITOR_KEY)) {
            RpcContext context = RpcContext.getContext(); // 提供方必须在invoke()之前获取context信息
            long start = System.currentTimeMillis(); // 记录起始时间戮
            getConcurrent(invoker, invocation).incrementAndGet(); // 并发计数
            try {
                Result result = invoker.invoke(invocation); // 让调用链往下执行
                collect(invoker, invocation, result, context, start, false);
                return result;
            } catch (RpcException e) {
                collect(invoker, invocation, null, context, start, true);
                throw e;
            } finally {
                getConcurrent(invoker, invocation).decrementAndGet(); // 并发计数
            }
        } else {
            return invoker.invoke(invocation);
        }
    }

 

13.ExtensionLoader的cachedDefaultName默认取接口的SPI里面的value值作为默认的扩展子类名字

所以在RegistryProtocol.refer方法中调用Cluster.join(Directory)即使Directory内的URL没有包含cluster的配置 也会直接

调用FailoverCluster的方法

@SPI(FailoverCluster.NAME)
public interface Cluster {

    /**
     * Merge the directory invokers to a virtual invoker.
     * 
     * @param 
     * @param directory
     * @return cluster invoker
     * @throws RpcException
     */
    @Adaptive
     Invoker join(Directory directory) throws RpcException;

}

14.ExtensionFactory  @Adaptive

在看ExtensionFactory的子类AdaptiveExtensionFactory的时候,发现了他的Class上有打了@Adaptive,然而其他两个子类并没有SpiExtensionFactory,SpringExtensionFactory,又重新看了一下ExtensionLoader初始化载入资源的方法

发现如果有标识@Adaptive的class会默认是这个SPI接口的实现类,而不会生成字节码通过入参去驱动具体子类,具体实现如下

ExtensionLoader line 633

                                            if (clazz.isAnnotationPresent(Adaptive.class)) {
                                                if(cachedAdaptiveClass == null) {
                                                    cachedAdaptiveClass = clazz;
                                                } else if (! cachedAdaptiveClass.equals(clazz)) {
                                                    throw new IllegalStateException("More than 1 adaptive class found: "
                                                            + cachedAdaptiveClass.getClass().getName()
                                                            + ", " + clazz.getClass().getName());
                                                }
                                            } 

ExtensionLoader line 727

    private Class getAdaptiveExtensionClass() {
        getExtensionClasses();
        if (cachedAdaptiveClass != null) {
            return cachedAdaptiveClass;
        }
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }

 

15.因为@Service没有元注解@Inherited,如果通过annotation方式启动dubbo的话,打了注解类有涉及切面的话都会启动不起来

16.@Adaptive 具有这个标识的class作为默认的实现子类

17.加了@Activate的注解,可以通过url里面配置{interface}=-xxx来禁止filter的某各类,或者xxx=(false 0 null N/A)来开启某个类

  比如 ProtocolFilterWrapper getActivateExtension

@Activate 有了value配置,则url中必须设置xxx=(false 0 null N/A) 来开启,没有value则默认开启 见 ExtensionLoader.getActivateExtension 暂时dubbo应用里面只有Filter、TelnetHandler和InvokerListener会用到

 

18.一些默认配置,优先读取jvm启动参数,如果没有则优先寻找dubbo.properties.file在jvm启动参数是否配置了路径,否则在环境变量里寻找dubbo.properties.file是否配置了value,否则默认取服务的dubbo.properties文件

19.消费端设置的配置优先级高于服务端

     /**
     * 合并url参数 顺序为override > -D >Consumer > Provider
     * @param providerUrl
     * @param overrides
     * @return
     */
    private URL mergeUrl(URL providerUrl){
    }

 

你可能感兴趣的:(Dubbo)