dubbo中“Wrapper”类

在dubbo中,有一种特殊类型的类,这种类含有一个复制构造函数,dubbo中把这种类型的类叫做Wrapper类,比如ProtocolFilterWrapper或者ProtocolListenerWrapper,它们都含有自身的复制构造函数,我们在调试dubbo的时候会发现,只要是Protocol的子类都会被这两个类“wrap”起来,那么在dubbo中是怎么实现这种功能的呢?下面通过代码来分析这个的实现过程。

首先,当ExtensionLoader调用loadExtensionClasses的时候,会依次加在如下三个目录中的配置文件:

loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);  
loadFile(extensionClasses, DUBBO_DIRECTORY);  
loadFile(extensionClasses, SERVICES_DIRECTORY);  

在loadFile中,有一段代码是这样的:

try {  
  clazz.getConstructor(type);
  Set<Class<?>> wrappers = cachedWrapperClasses;
  if (wrappers == null) {
    cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
    wrappers = cachedWrapperClasses;
  }
  wrappers.add(clazz);
} catch (NoSuchMethodException e) {}

这段代码的意思就是首先获得这个clazz的复制构造函数(在ExtensionLoader中,clazz一定是type的子类型),如果存在复制构造函数,则会把这个复制构造函数存起来,供之后用。

以Protocol.class为例,通过getAdaptiveExtension动态创建Protocol对象时,会生成如下代码,这里只列举了其中一个方法的代码:

// Extension生成的code
package com.alibaba.dubbo.rpc;  
import com.alibaba.dubbo.common.extension.ExtensionLoader;  
public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {  
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);  
}

}

分析代码会发现,会通过getExtension方法去找对应的实现,getExtension中有一个createExtension方法,createExtension方法如下:

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);
    }
}

在上面代码中可以发现,会用所有的wrapper class对protocol进行“wrap”,然后返回。这样就实现了在调用真正的Protocol对象之前,会首先调用wrapper类对象。

以上就是dubbo中wrapper类的实现方法。

Shaohang Zhao

Read more posts by this author.