Dubbo源码分析-Dubbo中的动态生成类

Dubbo源码分析-Dubbo中的动态生成类

  • 自适应扩展机制中的Adaptive类
    • 自适应扩展机制说明
    • Adaptive类实现自适应
    • SPI实现类的类型
    • 重要数据结构
  • 服务引用中的接口代理类
    • 服务引用的实现
    • 动态生成接口代理类的过程
    • 重要数据结构
  • 方便获取类信息的Wrapper
  • 版本

Dubbo中的动态生成类体现在如下几个方面:1. 自适应扩展机制中的Adaptive类;2. 服务引用的接口代理类;3. 方便获取类信息的Wrapper。他们具有不同的作用,下面逐一分析。

自适应扩展机制中的Adaptive类

自适应扩展机制是Dubbo对SPI机制(Service Provider Interface)的增强实现版,和API相比,在使用SPI时,调用方无需指定接口的具体实现,而在程序运行时决定。

自适应扩展机制说明

和原生SPI一样,在Dubbo的自适应扩展机制中,用META-INF目录下的配置文件指定接口实现类,配置文件名为接口的全限定类名。如下图,在dubbo-cluster包下的META-INF目录下,配置文件com.alibaba.dubbo.rpc.cluster.LoadBalance指定了四个接口实现,等号左边是实现类的name,等号右边是实现类的全限定类名。

// dubbo-cluster包中的配置文件com.alibaba.dubbo.rpc.cluster.LoadBalance
random=com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance
roundrobin=com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance
leastactive=com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance
consistenthash=com.alibaba.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance

在Dubbo中,自适应扩展机制主要由类ExtensionLoader实现,对于接口T(本例中的LoadBalance),ExtensionLoader提供getAdaptiveExtension()方法,返回接口T的自适应实现类实例,该类实现了接口T,作为所有其它接口T实现类的入口。在对接口T中注解了@Adaptive的方法进行调用时,自适应实现类实例根据调用方法的参数获取实现类的name,并调用getExtension(String name)获取相应类实例,使用相应方法完成调用。
在上面的例子中,调用通过自适应类的接口方法select时,如果参数url中关于负载均衡的参数使用了"roundrobin",那么自适应实现类对象会获取到RoundRobinLoadBalance的实例,并通过该实例调用select方法,实现特定的负载均衡策略。

@SPI(RandomLoadBalance.NAME)
public interface LoadBalance {
    @Adaptive("loadbalance")
    <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
}

Adaptive类实现自适应

如上所述,Dubbo中的自适应扩展机制是通过ExtensionLoader类实现的,其中,T是SPI接口,ExtensionLoader提供getAdaptiveExtension()方法,该方法返回一个自适应实现类的实例。这个自适应类可以是预先定义的,也可以是动态生成的。这里先认为这个自适应类是动态生成的,这符合大部分的场景,预定义实现类的情况将在下一节会详细描述。把这个动态生成的自适应类记为T$Adaptive,它是接口T的一个实现,作为接口T所有其它实现类的入口,完成了根据运行时动态传递的参数决定采用不同实现类实例的功能,是Dubbo实现SPI的关键点。下面举例说明

package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol {
    public void destroy() {throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
    }
    public int getDefaultPort() {throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
    }
    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;
        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])");
        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }
    public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
        if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
        if (arg0.getUrl() == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");com.alibaba.dubbo.common.URL url = arg0.getUrl();
        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])");
        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.export(arg0);
    }
}	

上面给出了一个T$Adaptive类的例子,该例中接口T为Protocol,Protocol$Adaptive实现了export和refer两个接口方法,实现的思路都是从export和refer的接口参数中获取Dubbo URL,然后根据URL中动态传递的protocol参数确定应用的Protocol实现类name,通过ExtensionLoader的getExtension(String name)方法获取该实现类的实例,调用具体实现类的export和refer方法。下面贴出了Protocol接口的定义代码,其中,注解@SPI(“dubbo”)表示该接口为一个SPI,并且默认实现类名称为dubbo;export和refer上的注解@Adaptive表示在增强类T$Adaptive的代码中实现这两个方法,没有注解@Adaptive的方法就不实现。

@SPI("dubbo")
public interface Protocol {
    int getDefaultPort();
    @Adaptive
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
    @Adaptive
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
    void destroy();
}

ExtensionLoader的getExtension(String name)方法代码贴出如下,ExtensionLoader先到缓存cachedInstances中看有没有name对应类的实例,有就直接返回,没有则调用createExtension(String name)创建一个。

    // ExtensionLoader
    public T getExtension(String name) {
        ...
        // 从缓存取, cachedInstances的key是类对应的name,value是实例
        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;
    }

createExtension(String name)代码如下,首先调用getExtensionClasses().get(name)获取名为name的类定义,然后以类定义为key从缓存EXTENSION_INSTANCES中取实例,有则返回,没有则创建一个,并用包裹类进行包裹。

    // ExtensionLoader
    private T createExtension(String name) {
        // 取类定义
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw findException(name);
        }
        try {
            // 从缓存取, EXTENSION_INSTANCES的key是类定义,value是实例
            // EXTENSION_INSTANCES 和 cachedInstances 都是实例的缓存,但是key不一样
            // dubbo的spi配置文件中,多个name可能对应同一个实现类的定义
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            injectExtension(instance);
            // 用包裹类嵌套
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
                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);
        }
    }

在getExtensionClasses中,根据指定的接口类型,扫描"META-INF/services/"、“META-INF/dubbo/”、"META-INF/dubbo/internal/"三个目录下关于该接口的实现类,加载到ExtensionLoader的成员cachedClasses中并返回,代码片段如下

    // ExtensionLoader
    private Map<String, Class<?>> getExtensionClasses() {
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    classes = loadExtensionClasses();
                    // 加载到cachedClasses
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }
    // ExtensionLoader
    private Map<String, Class<?>> loadExtensionClasses() {
        ......
        Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
        // 扫描META-INF/dubbo/internal/
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
        // 扫描META-INF/dubbo/
        loadDirectory(extensionClasses, DUBBO_DIRECTORY);
        // 扫描META-INF/services/
        loadDirectory(extensionClasses, SERVICES_DIRECTORY);
        return extensionClasses;
    }

综上所述,对于接口T,ExtensionLoader提供getAdaptiveExtension()方法,返回动态生成类T$Adaptive的实例,T$Adaptive实现了接口T,作为所有其它接口T实现类的入口,在对接口T中注解了@Adaptive的方法进行调用时,T$Adaptive的实现根据参数调用getExtension (String name)获取相应类的实例,调用相应实现方法完成调用。

SPI实现类的类型

Dubbo的自适应扩展机制中,把SPI的实现类分为三类:

  • 自适应实现类:如果接口T有自适实现类的实现,那么上述ExtensionLoader的getAdaptiveExtension()方法直接返回自适应类的实例,而不会动态生成T$Adaptive类。通过Dubbo中定义的注解,可以表示自适应类,例如,接口ExtensionFactory实现AdaptiveExtensionFactory具有注解@Adapitve,它是一个自适应类。
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
      ...
}
  • 包裹类:在上述的ExtensionLoader的getExtension(String name)方法中,生成name对应实现类的实例时(注意这个name不是类名,而是SPI配置文件中的key),会用包裹类逐一包裹,最后得到的实际上是经过层层包裹的实例。包裹类是通过是否具有构造函数来判断的,例如,Protocol的实现ProtocolListenerWrapper是一个包裹类,它具有构造函数,因此是一个包裹类。ProtocolListenerWrapper的内部对象protocol是用来存放被包裹的对象的;ProtocolListenerWrapper实现了接口方法export和refer,并进行了增强实现,在本例中ProtocolListenerWrapper进行了增加监听器的增强实现。
public class ProtocolListenerWrapper implements Protocol {
    private final Protocol protocol;
    public ProtocolListenerWrapper(Protocol protocol) {
        if (protocol == null) {
            throw new IllegalArgumentException("protocol == null");
        }
        this.protocol = protocol;
    }
    
    @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
            return protocol.export(invoker);
        }
        return new ListenerExporterWrapper<T>(protocol.export(invoker),
                Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
                        .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
    }

    @Override
    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)));
    }
  • 普通实现类:接口T的一般实现类,是功能实现的基本内容。一般使用ExtensionLoader的getExtension(name)方法获取实现类实例。普通类型的实现类可以用@Activate注解进行标注。@Activate注解指定两个必须的值,group和value。ExtensionLoader提供方法getActivateExtension获取多个标注了@Activate的实现类实例。该方法如下:group传入要匹配的组,和实现类@Activate注解里的group匹配,如果匹配上,且url里的参数parameters的key包含@Activate注解的value值(类似于parameters.keyset().contains(value)的意思),则返回列表中包含该实现类;根据key在url的parameters参数取值(parameters.get(key)),根据取值获取希望返回的实现类name列表,根据这些name调用ExtensionLoader的getExtension(name)方法获取实现类实例。
    public List<T> getActivateExtension(URL url, String key, String group) {
        String value = url.getParameter(key);
        return getActivateExtension(url, value == null || value.length() == 0 ? null : Constants.COMMA_SPLIT_PATTERN.split(value), group);
    }

在上面三种类型的实现类中:(1)在无法以固定模式动态生成接口T的自适应类T$Adaptive时,需要实现自适应实现类;(2)Wrap包裹类用于对接口实现类的功能进行增强,并不会通过getExtension(String name)接口直接获取;(3)普通实现类是基本功能的实现类,通过getExtension(String name)接口直接获取获取其实例,其中关于@Activate注解的用法可以参看Filter接口以及其实现类。

重要数据结构

public class ExtensionLoader<T> {
    // 接口T的类型
    private final Class<?> type;
    // 包裹类缓存,只保存包裹类型的实现类
    private Set<Class<?>> cachedWrapperClasses;
    // 自适应类缓存,只保存自适应类型的实现类,最多只能有一个
    private volatile Class<?> cachedAdaptiveClass = null;      
    // 自适应类实例缓存,只保存自适应类型的实现类实例,最多只能有一个
    private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
    // 实现类名称缓存,key为实现类的类型,value为实现类的name,只保存普通类型的实现类名称
    private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>();               
    // 实现类缓存,key为实现类的name,value为实现类,只保存普通类型的实现类
    private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();     
    // cachedInstances是实现类实例缓存,key为实现类的名称,value为实例,只有普通类型的实现类才会产生实例
    // EXTENSION_INSTANCES是实现类实例缓存,key为实现类的类型,value为实例,只有普通类型的实现类才会产生实例
    // cachedInstances和EXTENSION_INSTANCES相比,因为多个name可能对应到同一个实现类,所以cachedInstances应该比EXTENSION_INSTANCES多
    // cachedInstances中的多个value可能在EXTENSION_INSTANCES中是同一个value
    private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();        
    private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();
    // Activate注解缓存
    private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>();
    // 默认实现类名称,只能是普通类型的实现类
    private String cachedDefaultName;    
           
}

服务引用中的接口代理类

服务引用的实现

Dubbo对服务的引用是通过接口代理类实现的。

<dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService"/>

例如,按照上面xml进行配置,Dubbo会动态生成一个DemoService的接口代理类proxy0,该代理类的成员handler完成对所引用的实际服务的调用,包括本地调用和远程调用。同时,该代理类proxy0还实现了其它一些扩展接口,这些接口的也都通过handler的invoke方法实现。

public class proxy0 implements ClassGenerator.DC, EchoService, DemoService {
    public static Method[] methods;
    private InvocationHandler handler;
    public proxy0(InvocationHandler invocationHandler) {
        this.handler = invocationHandler;
    }
    public proxy0() {
    }
    public String sayHello(String string) {
        // 将参数存储到 Object 数组中
        Object[] arrobject = new Object[]{string};
        // 调用 InvocationHandler 实现类的 invoke 方法得到调用结果
        Object object = this.handler.invoke(this, methods[0], arrobject);
        // 返回调用结果
        return (String)object;
    }
    /** 回声测试方法 */
    public Object $echo(Object object) {
        Object[] arrobject = new Object[]{object};
        Object object2 = this.handler.invoke(this, methods[1], arrobject);
        return object2;
    }
}

如下给出了InvocationHandler的完整定义,InvocationHandler中包含一个成员invoker,invoker是对最终调用接口DemoService的层层封装,通过这些封装,可以完成额外的工作,包括上述扩展接口的功能。

public class InvokerInvocationHandler implements InvocationHandler {
    private final Invoker<?> invoker;
    public InvokerInvocationHandler(Invoker<?> handler) {
        this.invoker = handler;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        ...
        return invoker.invoke(new RpcInvocation(method, args)).recreate();
    }
}

动态生成接口代理类的过程

下面贴出了生成接口代理类的代码

    // JavassistProxyFactory
    public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
    }

首先看一下Proxy,Proxy的代码贴出如下,Proxy是一个抽象类:它有一个抽象方法newInstance,和一个静态方法getProxy。getProxy实际返回一个Proxy子类的实例,该子类实现了抽象方法newInstance。因此,上面JavassistProxyFactory中生成接口代理类实例的getProxy方法可以看做分为两步实现:第一步调用Proxy.getProxy(interfaces)得到一个Proxy子类的实例,这个Proxy子类是动态生成的;第二步调用子类实例的newInstance方法得到接口代理类实例,这个接口代理类也是动态生成的。

// Proxy 
public abstract class Proxy {
    ...
    public static Proxy getProxy(ClassLoader cl, Class<?>... ics) {...}
    ...
    abstract public Object newInstance(InvocationHandler handler);
    ... 
}

重要数据结构

public abstract class Proxy {
    ...
    // Proxy的子类缓存
    // 第一级Map的key是类加载器
    // 第二级Map的key是接口字符串,例如"com.alibaba.dubbo.demo.DemoService;com.alibaba.dubbo.rpc.service.EchoService;"
    // 第二级Map的可以理解为,可以生成某些接口代理类的Proxy子类
    private static final Map<ClassLoader, Map<String, Object>> ProxyCacheMap = new WeakHashMap<ClassLoader, Map<String, Object>>();
    ...
}

方便获取类信息的Wrapper

抽象Wrapper类提供静态方法makeWrapper,该静态方法返回一个Wrapper子类的实例,该子类是动态生成的,它实现了Wrapper的抽象方法,通过这些抽象方法,可以方便获取类c的各种属性,也可以对c的方法进行反射调用。

// Wrapper
private static Wrapper makeWrapper(Class<?> c){
...
}

下面是Wrapper的抽象方法

public abstract class Wrapper {
    abstract public String[] getPropertyNames();
    abstract public Class<?> getPropertyType(String pn);
    abstract public boolean hasProperty(String name);
    abstract public Object getPropertyValue(Object instance, String pn) throws NoSuchPropertyException, IllegalArgumentException;
    abstract public void setPropertyValue(Object instance, String pn, Object pv) throws NoSuchPropertyException, IllegalArgumentException;
    abstract public String[] getMethodNames();
    abstract public String[] getDeclaredMethodNames();
    abstract public Object invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args) throws NoSuchMethodException, InvocationTargetException;
}

版本

本文参考Dubbo2.6.8版本

你可能感兴趣的:(Dubbo)