咱們已知Adaptive是一個註解,經過 @Target({ElementType.TYPE, ElementType.METHOD}) 可知該註解能夠用在類定義或方法定義上。java
/** * Activate * <p/> * 對於能夠被框架中自動激活加載擴展,此Annotation用於配置擴展被自動激活加載條件。 * 好比,過濾擴展,有多個實現,使用Activate Annotation的擴展能夠根據條件被自動加載。 * <ol> * <li>{@link Activate#group()}生效的Group。具體的有哪些Group值由框架SPI給出。 * <li>{@link Activate#value()}在{@link com.alibaba.dubbo.common.URL}中Key集合中有,則生效。 * </ol> * <p> * <p/> * 底層框架SPI提供者經過{@link com.alibaba.dubbo.common.extension.ExtensionLoader}的{@link ExtensionLoader#getActivateExtension}方法 * 得到條件的擴展。 * * @author william.liangf * @author ding.lid * @export * @see SPI * @see ExtensionLoader * @see ExtensionLoader#getActivateExtension(com.alibaba.dubbo.common.URL, String[], String) */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface Activate { /** * Group過濾條件。 * <br /> * 包含{@link ExtensionLoader#getActivateExtension}的group參數給的值,則返回擴展。 * <br /> * 如沒有Group設置,則不過濾。 */ String[] group() default {}; /** * Key過濾條件。包含{@link ExtensionLoader#getActivateExtension}的URL的參數Key中有,則返回擴展。 * <p/> * 示例:<br/> * 註解的值 <code>@Activate("cache,validatioin")</code>, * 則{@link ExtensionLoader#getActivateExtension}的URL的參數有<code>cache</code>Key,或是<code>validatioin</code>則返回擴展。 * <br/> * 如沒有設置,則不過濾。 */ String[] value() default {}; /** * 排序信息,能夠不提供。 */ String[] before() default {}; /** * 排序信息,能夠不提供。 */ String[] after() default {}; /** * 排序信息,能夠不提供。 */ int order() default 0; }
它的設計目的是爲了實現Dubbo SPI 時用來固定已知的類和擴展未知類。spring
1.註解在接口的實現類上:表明人工實現,實現一個裝飾類,它主要用於固定已知類,目前整個系統只有兩個,AdaptiveCompiler、AdaptiveExtensionFactory。設計模式
@SPI("javassist") public interface Compiler { /** * Compile java source code. * * @param code Java source code * @param classLoader TODO * @return Compiled class */ Class<?> compile(String code, ClassLoader classLoader); }
項目繼承圖以下:app
a. 爲何AdaptiveCompiler這個類是固定已知的?
由於整個框架僅支持Javassist和JdkCompiler;
b. 爲何AdaptiveExtensionFactory這個類是固定已知的?
由於整個框架僅支持2個objFactory,一個是spi,另外一個是spring;框架
2.註解在方法上,表明自動生成和編譯一個動態的Adaptive類,每一個方法均可以根據方法參數動態獲取各自的擴展點,主要因爲SPI 獲取類爲不固定的位置的擴展類,因此設計了動態的$Adaptive類。jvm
例如 Protocol的spi類有injvm、dubbo、registry、filter、listener等不少未知擴展類,它設計了Protocol$Adaptive的類,再經過ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(spi類);來提取對象。ide
在dubbo中通常會首先經過ExtensionLoader.getAdaptiveExtension
獲取Adaptive擴展。這個方法會首先在擴展點接口的全部實現類中查找類上是否有含有@Adaptive
註解,若是有這樣的類直接返回該類的實例,若是沒有則會查找擴展點接口的方法是否有@Adaptive
註解並動態編譯一個類實現該接口並擴展這些含有@Adaptive
註解的方法。函數
代碼執行流程:ui
-----------------------getAdaptiveExtension() -->getAdaptiveExtension()//爲cachedAdaptiveInstance賦值 -->createAdaptiveExtension() -->getAdaptiveExtensionClass() -->getExtensionClasses()//爲cachedClasses 賦值 -->loadExtensionClasses() -->loadFile -->createAdaptiveExtensionClass()//自動生成和編譯一個動態的adpative類,這個類是一個代理類 -->ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension() -->compiler.compile(code, classLoader) -->injectExtension()//做用:進入IOC的反轉控制模式,實現了動態入注
Protocol
全部擴展實現類上都沒有@Adaptive
註解,且擴展接口含有兩個 @Adaptive
註解的方法:exporter() refer()
,因此dubbo會生成一個動態類Protocol$Adaptive
,且它實現Protocol
接口來擴展這兩個Adaptive方法。擴展點接口和最終動態生成Protocol$Adaptive類以下:this
@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(); }
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(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); } }
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );從arg0中解析出擴展點名稱extName,extName的默認值爲@SPI的value。這是adaptive的精髓:每個方法均可以根據方法參數動態獲取各自須要的擴展點。
Protocol extension =(Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).
getExtension(extName);根據extName從新獲取指定的Protocol.class擴展點。若是全部擴展點中含有Wrapper(listener,fiter)則ExtensionLoader.getExtension()會將真正的實現類經過Wrapper(listener,fiter)包裝後返回。
Dubbo擴展點AOP功能
對dubbo擴展點作切面功能的擴展,從ExtensionLoader的createExtension() 代碼提及:
@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; //begin if (wrapperClasses != null && wrapperClasses.size() > 0) { for (Class<?> wrapperClass : wrapperClasses) { instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); } } //end return instance; } catch (Throwable t) { throw new IllegalStateException("Extension instance(name: " + name + ", class: " + type + ") could not be instantiated: " + t.getMessage(), t); } }
關鍵說明,
1. cachedWrapperClasses是在loadFile裏面加載的,」WrapperClass」是符合某種特徵的擴展接口實現類的稱呼。例如ProtocolFilterWrapper
和ProtocolListenerWrapper。他們共同特徵就是帶有Protocol接口的構造函數。
/** * ListenerProtocol * * @author william.liangf */ public class ProtocolFilterWrapper implements Protocol { private final Protocol protocol; public ProtocolFilterWrapper(Protocol protocol) { if (protocol == null) { throw new IllegalArgumentException("protocol == null"); } this.protocol = protocol; } 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; } public int getDefaultPort() { return protocol.getDefaultPort(); } 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); } public void destroy() { protocol.destroy(); } }
遇到的設計模式