目錄java
@update:2016-06-28 00:44:46
@author:張三金 去哪兒網高級工程師
未完待續...緩存
若是要講dubbo源碼,那麼要從SPI開始(SPI自行google),由於dubbo全部的功能都是經過本身實現的一套SPI機制來擴展的,能夠理解爲dubbo的全部功能都拆分而且抽象爲interface,經過SPI查找這些interface的實現,而且經過url組合起來,就成了一個完整的rpc框架.app
ExtensionLoader是dubbo內部的SPI實現,dubbo的全部組件都經過ExtensionLoader獲取,本文以最多見的interface
Filter爲例,dubbo裏有不少的filter,而且支持碼農自定義filter,dubbo的filter全是經過SPI查找的,因此很是易於擴展.框架
com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper#buildInvokerChain方法中拿到當前service全部的filter的實現,而後執行.函數
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
getExtensionLoader方法會爲每個.class new 一個ExtensionLoader實例,並緩存起來ui
private ExtensionLoader(Class<?> type) { this.type = type; objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); }
在dubbo中,須要擴展的功能須要在其interface上打到@SPI註解
在dubbo SPI中,interface的一個實現叫作Extension,Extension實現了這個接口的功能,一個interface有許多的Extensionthis
AdaptiveExtension叫作適配Extension,一個AdaptiveExtension的做用是從全部的Extension中,根據當前的url配置策略,選出指定的的Extensiongoogle
上面的代碼經過getAdaptiveExtension()方法拿到當前interface的AdaptiveExtensionurl
首先會拿到全部的接口實現
code:ExtensionLoader#loadExtensionClasses
spa
private Map<String, Class<?>> loadExtensionClasses() { final SPI defaultAnnotation = type.getAnnotation(SPI.class); if (defaultAnnotation != null) { String value = defaultAnnotation.value(); if (value != null && (value = value.trim()).length() > 0) { String[] names = NAME_SEPARATOR.split(value); if (names.length > 1) { throw new IllegalStateException("more than 1 default extension name on extension " + type.getName() + ": " + Arrays.toString(names)); } if (names.length == 1) cachedDefaultName = names[0]; } } Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>(); loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY); loadFile(extensionClasses, DUBBO_DIRECTORY); loadFile(extensionClasses, SERVICES_DIRECTORY); return extensionClasses; }
loadExtensionClasses
loadFile會到3個目錄下把全部的接口實現類加載進來
例以下面爲dubbo內部實現filter的SPI文件
file:META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Filter
echo=com.alibaba.dubbo.rpc.filter.EchoFilter generic=com.alibaba.dubbo.rpc.filter.GenericFilter genericimpl=com.alibaba.dubbo.rpc.filter.GenericImplFilter token=com.alibaba.dubbo.rpc.filter.TokenFilter accesslog=com.alibaba.dubbo.rpc.filter.AccessLogFilter activelimit=com.alibaba.dubbo.rpc.filter.ActiveLimitFilter classloader=com.alibaba.dubbo.rpc.filter.ClassLoaderFilter context=com.alibaba.dubbo.rpc.filter.ContextFilter consumercontext=com.alibaba.dubbo.rpc.filter.ConsumerContextFilter exception=com.alibaba.dubbo.rpc.filter.ExceptionFilter executelimit=com.alibaba.dubbo.rpc.filter.ExecuteLimitFilter deprecated=com.alibaba.dubbo.rpc.filter.DeprecatedFilter compatible=com.alibaba.dubbo.rpc.filter.CompatibleFilter timeout=com.alibaba.dubbo.rpc.filter.TimeoutFilter monitor=com.alibaba.dubbo.monitor.support.MonitorFilter validation=com.alibaba.dubbo.validation.filter.ValidationFilter cache=com.alibaba.dubbo.cache.filter.CacheFilter trace=com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter future=com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter
SPI文件給出了全部實現的徹底限定類名,那麼能夠經過反射機制加載對應的Class
Class<?> clazz = Class.forName(line, true, classLoader);
加載的Class會被歸爲3類
Holder<Map<String, Class<?>>> cachedClasses
持有其引用Class<?> cachedAdaptiveClass
持有其引用Set<Class<?>> cachedWrapperClasses
持有其引用加載AdaptiveExtension,經過判斷@Adaptive註解
if (clazz.isAnnotationPresent(Adaptive.class)) { if(cachedAdaptiveClass == null) { cachedAdaptiveClass = clazz; } else if (! cachedAdaptiveClass.equals(clazz)) { throw new IllegalStateException("More than 1 adaptive class found: " + cachedAdaptiveClass.getClass().getName() + ", " + clazz.getClass().getName()); } }
加載wrapper extension
try { clazz.getConstructor(type); Set<Class<?>> wrappers = cachedWrapperClasses; if (wrappers == null) { cachedWrapperClasses = new ConcurrentHashSet<Class<?>>(); wrappers = cachedWrapperClasses; } wrappers.add(clazz); } catch (NoSuchMethodException e) { //不是wrapper extension }
前面兩個都不是,那就是Extension,直接放入Holder<Map<String, Class<?>>> cachedClasses
SPI註解標記在interface上,表示這個interface的實現經過SPI加載,value表示有多個實現時,默認使用指明的實現
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface SPI { /** * 缺省擴展點名。 */ String value() default ""; }
@SPI public interface Filter { Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException; }