【知识库】--dubbo SPI 动态扩展点之getAdaptiveExtension()触发调用链(267)

来源:互联网 发布:linux 命令输出到变量 编辑:程序博客网 时间:2024/06/06 20:59

 已知 com.alibaba.dubbo.common.extension.ExtensionLoader :

* <li>自动注入关联扩展点。</li>* <li>自动Wrap上扩展点的Wrap类。</li>* <li>缺省获得的的扩展点是一个Adaptive Instance。
而在dubbo.internal文件下  (dubbo/3.1.11/dubbo-3.1.11.jar!/META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol)里面包含如下两个wrapper

filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapperlistener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper

com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper wrap调用链

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {    if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {        return protocol.export(invoker);    }    return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));}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);}
调用链--链接
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {    Invoker<T> last = invoker;    List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);    if (filters.size() > 0) {        for (int i = filters.size() - 1; i >= 0; i --) {            final Filter filter = filters.get(i);            final Invoker<T> next = last;            last = new Invoker<T>() {                public Class<T> getInterface() {                    return invoker.getInterface();                }                public URL getUrl() {                    return invoker.getUrl();                }                public boolean isAvailable() {                    return invoker.isAvailable();                }                public Result invoke(Invocation invocation) throws RpcException {                    return filter.invoke(next, invocation);                }                public void destroy() {                    invoker.destroy();                }                @Override                public String toString() {                    return invoker.toString();                }            };        }    }    return last;}

问题来了:他们在哪里触发?

1从如下地方开始(举例)

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

2 getAdaptiveExtention() 方法

@SuppressWarnings("unchecked")public T getAdaptiveExtension() {    Object instance = cachedAdaptiveInstance.get();    if (instance == null) {        if (createAdaptiveInstanceError == null) {            synchronized (cachedAdaptiveInstance) {                instance = cachedAdaptiveInstance.get();                if (instance == null) {                    try {                        instance = createAdaptiveExtension();继续分析                        cachedAdaptiveInstance.set(instance);                    } catch (Throwable t) {                        createAdaptiveInstanceError = t;                        throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);                    }                }            }        } else {            throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);        }    }    return (T) instance;}

3  createAdaptiveExtension() 方法

@SuppressWarnings("unchecked")private T createAdaptiveExtension() {    try {        return injectExtension((T) getAdaptiveExtensionClass().newInstance());    } catch (Exception e) {        throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e);    }}

4 Class<?> getAdaptiveExtensionClass() 方法

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

5 Class<?> createAdaptiveExtensionClass() 方法

private Class<?> createAdaptiveExtensionClass() {    String code = createAdaptiveExtensionClassCode();    ClassLoader classLoader = findClassLoader();    com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();    return compiler.compile(code, classLoader);}

6 重点:生成代码code

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 = (%<s)%s.getExtensionLoader(%s.class).getExtension(extName);",                    type.getName(), ExtensionLoader.class.getSimpleName(), type.getName());            code.append(s);            // return statement            if (!rt.equals(void.class)) {                code.append("\nreturn ");            }            s = String.format("extension.%s(", method.getName());            code.append(s);            for (int i = 0; i < pts.length; i++) {                if (i != 0)                    code.append(", ");                code.append("arg").append(i);            }            code.append(");");        }        codeBuidler.append("\npublic " + rt.getCanonicalName() + " " + method.getName() + "(");        for (int i = 0; i < pts.length; i++) {            if (i > 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();}

7 上面生成的代码中 有如下一段

s = String.format("\n%s extension = (%<s)%s.getExtensionLoader(%s.class).getExtension(extName);",        type.getName(), ExtensionLoader.class.getSimpleName(), type.getName());

8 这里就是触发wrap的源头:如下方法

/** * 返回指定名字的扩展。如果指定名字的扩展不存在,则抛异常 {@link IllegalStateException}. * * @param name * @return */@SuppressWarnings("unchecked")public T getExtension(String name) {    if (name == null || name.length() == 0)        throw new IllegalArgumentException("Extension name == null");    if ("true".equals(name)) {        return getDefaultExtension();    }    Holder<Object> holder = cachedInstances.get(name);    if (holder == null) {        cachedInstances.putIfAbsent(name, new Holder<Object>());        holder = cachedInstances.get(name);    }    Object instance = holder.get();    if (instance == null) {        synchronized (holder) {            instance = holder.get();            if (instance == null) {                instance = createExtension(name);                holder.set(instance);            }        }    }    return (T) instance;}


9 根据名字扩展:(这里的名字其实就是协议中的关键字如zookeeper,dubbo等)

@SuppressWarnings("unchecked")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<Class<?>> 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);    }}

10 上面方法中的代码片段:解释了com.alibaba.dubbo.common.extension.ExtensionLoader的注释(wrap)

injectExtension(instance);//自动注入关联扩展点。Set<Class<?>> wrapperClasses = cachedWrapperClasses;if (wrapperClasses != null && wrapperClasses.size() > 0) {    for (Class<?> wrapperClass : wrapperClasses) {//自动Wrap上扩展点的Wrap类。        instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));    }}

11 最终验证 本文一开始讲解的两个wrapper类,第一个就是负责责任链的链接

filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapperlistener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper

12 附加 dubbo 3.1.11 的filter列表

adminzkfilter=com.alibaba.dubbo.registry.filter.AdminZkServiceFiltermonitor=com.alibaba.dubbo.monitor.support.MonitorFiltervalidation=com.alibaba.dubbo.validation.filter.ValidationFiltercache=com.alibaba.dubbo.cache.filter.CacheFiltertrace=com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilterfuture=com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilterecho=com.alibaba.dubbo.rpc.filter.EchoFiltergeneric=com.alibaba.dubbo.rpc.filter.GenericFiltergenericimpl=com.alibaba.dubbo.rpc.filter.GenericImplFiltertoken=com.alibaba.dubbo.rpc.filter.TokenFilteraccesslog=com.alibaba.dubbo.rpc.filter.AccessLogFilteractivelimit=com.alibaba.dubbo.rpc.filter.ActiveLimitFilterclassloader=com.alibaba.dubbo.rpc.filter.ClassLoaderFiltercontext=com.alibaba.dubbo.rpc.filter.ContextFilterconsumercontext=com.alibaba.dubbo.rpc.filter.ConsumerContextFilterexception=com.alibaba.dubbo.rpc.filter.ExceptionFilterexecutelimit=com.alibaba.dubbo.rpc.filter.ExecuteLimitFilterdeprecated=com.alibaba.dubbo.rpc.filter.DeprecatedFiltercompatible=com.alibaba.dubbo.rpc.filter.CompatibleFiltertimeout=com.alibaba.dubbo.rpc.filter.TimeoutFilter

原创粉丝点击