咱们已知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(); } }
遇到的设计模式