说明
dubboSPI扩展点
项目结构
SPI注解
@SPI
/** * 标识一个接口是否是@SPI接口 */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface SPI { /** * 默认的SPI实现key */ String value() default ""; }
如:
@SPI("dubbo") public interface Protocol { // ... 省略代码 }
@Adaptive
可以标记在类上 也可以标记在方法上
标记在类上:表示是我们手动实现装饰类 只能有一个 具体可以看<1>例子
标记在方法上:会通过javasist动态生成一个类 对于方法的实现会根据参数传过来的key动态获取url 具体可以看<1>例子
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface Adaptive { /** * Decide which target extension to be injected. The name of the target extension is decided by the parameter passed * in the URL, and the parameter names are given by this method. * <p> * If the specified parameters are not found from {@link URL}, then the default extension will be used for * dependency injection (specified in its interface's {@link SPI}). * <p> * For examples, given <code>String[] {"key1", "key2"}</code>: * <ol> * <li>find parameter 'key1' in URL, use its value as the extension's name</li> * <li>try 'key2' for extension's name if 'key1' is not found (or its value is empty) in URL</li> * <li>use default extension if 'key2' doesn't appear either</li> * <li>otherwise, throw {@link IllegalStateException}</li> * </ol> * If default extension's name is not give on interface's {@link SPI}, then a name is generated from interface's * class name with the rule: divide classname from capital char into several parts, and separate the parts with * dot '.', for example: for {@code com.alibaba.dubbo.xxx.YyyInvokerWrapper}, its default name is * <code>String[] {"yyy.invoker.wrapper"}</code>. This name will be used to search for parameter from URL. * * @return parameter key names in URL * 用于打在方法上动态javasist动态生成的装饰类 方法 url.getParameter(key)就是这里配置 */ String[] value() default {}; }
@Activate
打了此类的注解将会自动加载
com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper#buildInvokerChain
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface Activate { /** * 激活当前扩展类的条件之一, 该group参数将会与ExtensionLoader#getActivateExtension方法传入的gruop参数进行匹配 * @return 要匹配的组名 * @see ExtensionLoader#getActivateExtension(URL, String, String) */ String[] group() default {}; /** 当URL中出现该value值时激活扩展类 例如:@Activate("cache, validation")注释在一个接口上,当URL中有cache或者validation参数时激活 * @return URL对应的参数的keys * @see ExtensionLoader#getActivateExtension(URL, String) * @see ExtensionLoader#getActivateExtension(URL, String, String) */ String[] value() default {}; /** * 排序信息,可选 * @return 在当前扩展类执行之前的扩展类 */ String[] before() default {}; /** * 排序信息,可选 * @return 在当前扩展类执行之后的扩展类 */ String[] after() default {}; /** * 当前类执行的权重,越小越先执行 */ int order() default 0; }
如dubbo几个Filter的实现
/** * LimitInvokerFilter * 当group group 同时配置了actives=*就会返回此过滤器 methodParameter含有actives */ @Activate(group = Constants.CONSUMER, value = Constants.ACTIVES_KEY) public class ActiveLimitFilter implements Filter {
/** * CacheFilter * group为consumer或者provider 同时 含有cache=*的配置的时候 返回此过滤器 methodParametr含有activies */ @Activate(group = {Constants.CONSUMER, Constants.PROVIDER}, value = Constants.CACHE_KEY) public class CacheFilter implements Filter { }
getExtension(name)加载过程
//adaptive javasist生成例子 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) //<18> ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName); return extension.export(arg0);
getAdaptiveExtension加载过程
/** * 获取Protocol Spi实现对象 * <2>getExtensionLoader <3>getAdaptiveExtension */ private static final Protocol protocol = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
getActivateExtension(url,key,group)加载过程
com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper#buildInvokerChain
//<16>获取激活对象 参数如:key service.filter gruop=provider List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
ExtensionLoader
静态变量
//==============================静态变量 //[1]扫描服务实现的文件存放 private static final String SERVICES_DIRECTORY = "META-INF/services/"; //[2]扫描服务实现的文件存放 private static final String DUBBO_DIRECTORY = "META-INF/dubbo/"; //[3]dubbo内置的spi服务实现 private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/"; //[5]spi配置分割符号,分割 比如 key=fullClassName1,fullClassName2 private static final Pattern NAME_SEPARATOR = Pattern.compile("\s*[,]+\s*"); /*** * [6]每个class类都会创建一个对应ExtensionLoader ExtnsionLoader实例不用每次都加载 * 如我们常常在dubbo看到这样的代码 * private static final Protocol protocol =(Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); */ private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>(); /** * [7]各个class和实现的定义 比如 key * key:com.alibaba.dubbo.rpc.Protocol vaue=实例对象 */ private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();
成员变量
// =============================成员变量 /*** *[8] ExtensionLoader.getExtensionLoader(Protocol.class) * 存的就是Protocol.class */ private final Class<?> type; //[9]创建对象工厂 默认2种实现SPIExtensionFactory SpringExtensionFactory 一个是扫描文件加载 一个在spring容器查找 private final ExtensionFactory objectFactory; /** * [10]spi配置 key:class value:name * 比如 spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory * key:com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory value:spi */ private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>(); //[11]Holder内部维护了map 与cachedNames相反 key=spi配置key vlaue:spi配置类的class private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>(); //[12]当前类的适配类集合如Filter的实现ExceptonFilter CacheFitler等 //key等于@Activate配置的value value等于注解信息 private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>(); /** * [12]存储当前接口class实现类的对象 * 每次实例化都会存入缓存 避免重复创建 下次直接从缓存拿 * ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("injvm") * ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("dubbo") */ private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>(); //Spi接口打上了@Adaptive的类的实例 private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>(); //Spi接口打上了@Adaptive的类的class private volatile Class<?> cachedAdaptiveClass = null; //spi接口配置的 value 如:@SPI("jvalidation") private String cachedDefaultName; private volatile Throwable createAdaptiveInstanceError; /** * 拓展 Wrapper 实现类集合 * <p> * 带唯一参数为拓展接口的构造方法的实现类 * <p> * 通过 {@link #loadExtensionClasses} 加载 */ private Set<Class<?>> cachedWrapperClasses; private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<String, IllegalStateException>();
<2>getExtensionLoader
静态方法
@SuppressWarnings("unchecked") public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) { //如果没有传class抛出错误 if (type == null) throw new IllegalArgumentException("Extension type == null"); //如果不是接口报错 if (!type.isInterface()) { throw new IllegalArgumentException("Extension type(" + type + ") is not interface!"); } //如果没有打上@Spi接口报错 if (!withExtensionAnnotation(type)) { throw new IllegalArgumentException("Extension type(" + type + ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!"); } //尝试从缓存获取 ExtentionLoader静态变量[6] ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type); if (loader == null) { //第一次获取会new一个并存入缓存<3> EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type)); loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type); } return loader; }
<3>ExtensionLoader(Class<T> type)
private ExtensionLoader(Class<?> type) { //存入成语变量[8] this.type = type; //type实例的创建工厂 可以发现也是一个SPI扩展 如果不是ExtensionFactory.class才加载工厂 用于创建type实例 工厂定义请看<4> getAdaptiveExtension请看<5> objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); }
<5>getAdaptiveExtension
@SuppressWarnings("unchecked") public T getAdaptiveExtension() { /** * 从成员变量获取适配类 避免重复获取 * 分为类上打:@Adaptive 打上Lee@Adaptive的对象 * 和方法打:@Adaptive 方法打就是javasisit动态生成的装饰类对象 */ Object instance = cachedAdaptiveInstance.get(); if (instance == null) { //未加载成功的原因是发生了异常。为null表示未加载 非null表示加载过程中出现异常 直接抛出 if (createAdaptiveInstanceError == null) { //加锁 避免重复加载 synchronized (cachedAdaptiveInstance) { instance = cachedAdaptiveInstance.get(); //二次判断避免锁穿透 if (instance == null) { try { //<6>创建适配器类对象 instance = createAdaptiveExtension(); cachedAdaptiveInstance.set(instance); } catch (Throwable t) { //创建适配器对象出错 存起来 下次再加载直接抛错 createAdaptiveInstanceError = t; throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t); } } } } else { throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError); } } return (T) instance; }
<6>createAdaptiveExtension
private T createAdaptiveExtension() { try { //获取SPI适配类 <15>injectExtension完成依赖注入 <7>getAdaptiveExtensionClass return injectExtension((T) getAdaptiveExtensionClass().newInstance()); } catch (Exception e) { throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e); } }
<7>getAdaptiveExtensionClass
private Class<?> getAdaptiveExtensionClass() { //<8>加载SPI配置信息 getExtensionClasses(); //如果当前spi接口含有@Adaptive的实现类 则直接返回 if (cachedAdaptiveClass != null) { return cachedAdaptiveClass; } //<13>根据javaSisit动态生成适配class return cachedAdaptiveClass = createAdaptiveExtensionClass(); }
<8>getExtensionClasses
private Map<String, Class<?>> getExtensionClasses() { //从缓存获取当前ExtensionLoader的所有spi配置映射 key为spi文件配置的key value为 spi文件配置的class全名称 //避免重复加载spi文件 Map<String, Class<?>> classes = cachedClasses.get(); if (classes == null) { synchronized (cachedClasses) { //避免锁穿透 classes = cachedClasses.get(); if (classes == null) { //<9>加载spi文件 classes = loadExtensionClasses(); cachedClasses.set(classes); } } } return classes; }
<9>loadExtensionClasses
private Map<String, Class<?>> loadExtensionClasses() { //获得SPI注解 type对应成员变量[8] final SPI defaultAnnotation = type.getAnnotation(SPI.class); if (defaultAnnotation != null) { //获得spi配置的value 如Protocol 配置的"dubbo" String value = defaultAnnotation.value(); if ((value = value.trim()).length() > 0) { //防止,号分割配置多个 对应静态变量[5] 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)); } //设置到 对应成员变量 [12] +3 if (names.length == 1) cachedDefaultName = names[0]; } } Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>(); //在一下几个目录扫描SPI配置 所以们自定义SPI配置可以定义在以下几个目录 //<10>加载dubbo 内置spi META-INF/dubbo/internal/ loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY); //<10>META-INF/dubbo/ loadDirectory(extensionClasses, DUBBO_DIRECTORY); //<10>META-INF/services/ loadDirectory(extensionClasses, SERVICES_DIRECTORY); return extensionClasses; }
<10>loadDirectory
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) { //spi文件必须为 目录+SPI注解的fullName String fileName = dir + type.getName(); try { Enumeration<java.net.URL> urls; ClassLoader classLoader = findClassLoader(); if (classLoader != null) { urls = classLoader.getResources(fileName); } else { urls = ClassLoader.getSystemResources(fileName); } if (urls != null) { while (urls.hasMoreElements()) { java.net.URL resourceURL = urls.nextElement(); //<11>这里最终会将SPI扫描 并将class封装到extensionClasses key为SPI文件key value为Spi文件配置的CLASS loadResource(extensionClasses, classLoader, resourceURL); } } } catch (Throwable t) { logger.error("Exception when load extension class(interface: " + type + ", description file: " + fileName + ").", t); } }
<11>loadResource
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) { try { //读取文件 BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), "utf-8")); try { String line; //逐行遍历如:adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory while ((line = reader.readLine()) != null) { //如果有#分割符号 则去掉#分隔符后之后数据 //如adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory#method //则会读取adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory final int ci = line.indexOf('#'); if (ci >= 0) line = line.substring(0, ci); //清除左右空格 line = line.trim(); //避免配置空行 if (line.length() > 0) { try { String name = null; int i = line.indexOf('='); if (i > 0) { //获取key name = line.substring(0, i).trim(); //获取value line = line.substring(i + 1).trim(); } if (line.length() > 0) { //<12>加载class 第一个参数为集合 第二个参数为反射创建 第三个参数为key loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name); } } catch (Throwable t) { IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t); exceptions.put(line, e); } } } } finally { reader.close(); } } catch (Throwable t) { logger.error("Exception when load extension class(interface: " + type + ", class file: " + resourceURL + ") in " + resourceURL, t); } }
<12>loadClass
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException { //判断spi配置 是不是当前SPI接口的实现类 if (!type.isAssignableFrom(clazz)) { throw new IllegalStateException("Error when load extension class(interface: " + type + ", class line: " + clazz.getName() + "), class " + clazz.getName() + "is not subtype of interface."); } //判断class是否打了@Adaptive注解 如果打了那么就是手动装饰类 //并存入成员变量[15] 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()); } //当前类是否含有构造函数 并且为当前SPI接口 装饰者 具体可以参考 } else if (isWrapperClass(clazz)) { Set<Class<?>> wrappers = cachedWrapperClasses; if (wrappers == null) { //对应成员变量18 cachedWrapperClasses = new ConcurrentHashSet<Class<?>>(); wrappers = cachedWrapperClasses; } wrappers.add(clazz); } else { //是否含有无参数构造函数 clazz.getConstructor(); if (name == null || name.length() == 0) { name = findAnnotationName(clazz); if (name.length() == 0) { throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL); } } //,分割 String[] names = NAME_SEPARATOR.split(name); if (names != null && names.length > 0) { Activate activate = clazz.getAnnotation(Activate.class); //是否是打了@Activate注解 if (activate != null) { //如果打了则存入成员变量[12] cachedActivates.put(names[0], activate); } for (String n : names) { if (!cachedNames.containsKey(clazz)) { //存入成员变量[10] cachedNames.put(clazz, n); } //存入extensionClasses key为name value为class 也就是成员变量[11]cachedClasses Class<?> c = extensionClasses.get(n); if (c == null) { extensionClasses.put(n, clazz); } else if (c != clazz) { throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName()); } } } } }
<13>createAdaptiveExtensionClass
private Class<?> createAdaptiveExtensionClass() { //<14>获得动态生成的java字符串 String code = createAdaptiveExtensionClassCode(); ClassLoader classLoader = findClassLoader(); //编译成class com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); return compiler.compile(code, classLoader); }
<14>createAdaptiveExtensionClassCode
private String createAdaptiveExtensionClassCode() { StringBuilder codeBuilder = new StringBuilder(); //反射获得SPI接口的所有方法 Method[] methods = type.getMethods(); //判断是否有含有打上@Adaptive的方法 boolean hasAdaptiveAnnotation = false; for (Method m : methods) { if (m.isAnnotationPresent(Adaptive.class)) { hasAdaptiveAnnotation = true; break; } } // no need to generate adaptive class since there's no adaptive method found. //如果SPI接口没有打上了@Adaptive的方法 则抛出异常 if (!hasAdaptiveAnnotation) throw new IllegalStateException("No adaptive method on extension " + type.getName() + ", refuse to create the adaptive class!"); codeBuilder.append("package ").append(type.getPackage().getName()).append(";"); codeBuilder.append(" import ").append(ExtensionLoader.class.getName()).append(";"); codeBuilder.append(" public class ").append(type.getSimpleName()).append("$Adaptive").append(" implements ").append(type.getCanonicalName()).append(" {"); for (Method method : methods) { //获取方法返回类型 Class<?> rt = method.getReturnType(); //获取方法参数 Class<?>[] pts = method.getParameterTypes(); //获取方法异常类型 Class<?>[] ets = method.getExceptionTypes(); //获取方法@Adaptive注解 Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class); StringBuilder code = new StringBuilder(512); if (adaptiveAnnotation == null) { code.append("throw new UnsupportedOperationException("method ") .append(method.toString()).append(" of interface ") .append(type.getName()).append(" is not adaptive method!");"); } else { int urlTypeIndex = -1; //获取方法的ULR类型参数所在索引 for (int i = 0; i < pts.length; ++i) { if (pts[i].equals(URL.class)) { urlTypeIndex = i; break; } } //如果含有URL参数则生成非空判断 // found parameter in URL type if (urlTypeIndex != -1) { // Null Point check 如:if (arg1 == null) throw new IllegalArgumentException("url == null"); String s = String.format(" if (arg%d == null) throw new IllegalArgumentException("url == null");", urlTypeIndex); code.append(s); //如:com.alibaba.dubbo.common.URL url = arg1; s = String.format(" %s url = arg%d;", URL.class.getName(), urlTypeIndex); code.append(s); } // did not find parameter in URL type else { String attribMethod = null; // find URL getter method LBL_PTS: for (int i = 0; i < pts.length; ++i) { Method[] ms = pts[i].getMethods(); for (Method m : ms) { String name = m.getName(); if ((name.startsWith("get") || name.length() > 3) && Modifier.isPublic(m.getModifiers()) && !Modifier.isStatic(m.getModifiers()) && m.getParameterTypes().length == 0 && m.getReturnType() == URL.class) { urlTypeIndex = i; attribMethod = name; break LBL_PTS; } } } if (attribMethod == null) { throw new IllegalStateException("fail to create adaptive class for interface " + type.getName() + ": not found url parameter or url attribute in parameters of method " + method.getName()); } // Null point check String s = String.format(" if (arg%d == null) throw new IllegalArgumentException("%s argument == null");", urlTypeIndex, pts[urlTypeIndex].getName()); code.append(s); s = String.format(" if (arg%d.%s() == null) throw new IllegalArgumentException("%s argument %s() == null");", urlTypeIndex, attribMethod, pts[urlTypeIndex].getName(), attribMethod); code.append(s); s = String.format("%s url = arg%d.%s();", URL.class.getName(), urlTypeIndex, attribMethod); code.append(s); } String[] value = adaptiveAnnotation.value(); // value is not set, use the value generated from class name as the key if (value.length == 0) { char[] charArray = type.getSimpleName().toCharArray(); StringBuilder sb = new StringBuilder(128); for (int i = 0; i < charArray.length; i++) { if (Character.isUpperCase(charArray[i])) { if (i != 0) { sb.append("."); } sb.append(Character.toLowerCase(charArray[i])); } else { sb.append(charArray[i]); } } value = new String[]{sb.toString()}; } boolean hasInvocation = false; for (int i = 0; i < pts.length; ++i) { if (pts[i].getName().equals("com.alibaba.dubbo.rpc.Invocation")) { // Null Point check String s = String.format(" if (arg%d == null) throw new IllegalArgumentException("invocation == null");", i); code.append(s); s = String.format(" String methodName = arg%d.getMethodName();", i); code.append(s); hasInvocation = true; break; } } String defaultExtName = cachedDefaultName; String getNameCode = null; for (int i = value.length - 1; i >= 0; --i) { if (i == value.length - 1) { if (null != defaultExtName) { if (!"protocol".equals(value[i])) if (hasInvocation) getNameCode = String.format("url.getMethodParameter(methodName, "%s", "%s")", value[i], defaultExtName); else getNameCode = String.format("url.getParameter("%s", "%s")", value[i], defaultExtName); else getNameCode = String.format("( url.getProtocol() == null ? "%s" : url.getProtocol() )", defaultExtName); } else { if (!"protocol".equals(value[i])) if (hasInvocation) getNameCode = String.format("url.getMethodParameter(methodName, "%s", "%s")", value[i], defaultExtName); else getNameCode = String.format("url.getParameter("%s")", value[i]); else getNameCode = "url.getProtocol()"; } } else { if (!"protocol".equals(value[i])) if (hasInvocation) getNameCode = String.format("url.getMethodParameter(methodName, "%s", "%s")", value[i], defaultExtName); else getNameCode = String.format("url.getParameter("%s", %s)", value[i], getNameCode); else getNameCode = String.format("url.getProtocol() == null ? (%s) : url.getProtocol()", getNameCode); } } code.append(" String extName = ").append(getNameCode).append(";"); // check extName == null? String s = String.format(" if(extName == null) " + "throw new IllegalStateException("Fail to get extension(%s) name from url(" + url.toString() + ") use keys(%s)");", type.getName(), Arrays.toString(value)); code.append(s); s = String.format(" %s extension = (%<s)%s.getExtensionLoader(%s.class).getExtension(extName);", type.getName(), ExtensionLoader.class.getSimpleName(), type.getName()); code.append(s); // return statement if (!rt.equals(void.class)) { code.append(" return "); } s = String.format("extension.%s(", method.getName()); code.append(s); for (int i = 0; i < pts.length; i++) { if (i != 0) code.append(", "); code.append("arg").append(i); } code.append(");"); } codeBuilder.append(" public ").append(rt.getCanonicalName()).append(" ").append(method.getName()).append("("); for (int i = 0; i < pts.length; i++) { if (i > 0) { codeBuilder.append(", "); } codeBuilder.append(pts[i].getCanonicalName()); codeBuilder.append(" "); codeBuilder.append("arg").append(i); } codeBuilder.append(")"); if (ets.length > 0) { codeBuilder.append(" throws "); for (int i = 0; i < ets.length; i++) { if (i > 0) { codeBuilder.append(", "); } codeBuilder.append(ets[i].getCanonicalName()); } } codeBuilder.append(" {"); codeBuilder.append(code.toString()); codeBuilder.append(" }"); } codeBuilder.append(" }"); if (logger.isDebugEnabled()) { logger.debug(codeBuilder.toString()); } return codeBuilder.toString(); }
<15>injectExtension
/* 完成动态注入 * @param instance * @return */ private T injectExtension(T instance) { try { if (objectFactory != null) { //获得SPI类所有包含一个参数的Set方法 同时是公共的 for (Method method : instance.getClass().getMethods()) { if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 && Modifier.isPublic(method.getModifiers())) { /** * Check {@link DisableInject} to see if we need auto injection for this property * * 如果打了DisableInject注解则不注入 */ if (method.getAnnotation(DisableInject.class) != null) { continue; } //获取 Class<?> pt = method.getParameterTypes()[0]; try { //剔除set 比如setDefaultCompiler 取出defaultCompiler String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : ""; //对象工厂获取实例 Object object = objectFactory.getExtension(pt, property); if (object != null) { method.invoke(instance, object); } } catch (Exception e) { logger.error("fail to inject via method " + method.getName() + " of interface " + type.getName() + ": " + e.getMessage(), e); } } } } } catch (Exception e) { logger.error(e.getMessage(), e); } return instance; }
<16>getActivateExtension
public List<T> getActivateExtension(URL url, String key, String group) { //从url获取指定key的参数 比如provider传入的filter就是server.filter String value = url.getParameter(key); //<17>传入url 指定key获取的value 多个,号隔开 return getActivateExtension(url, value == null || value.length() == 0 ? null : Constants.COMMA_SPLIT_PATTERN.split(value), group); }
<17>getActivateExtension
public List<T> getActivateExtension(URL url, String[] values, String group) { List<T> exts = new ArrayList<T>(); //url配置对应key的value List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values); //加载默认的 是否包含指定key value=-default的配置 -default忽略默认配置 if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) { //<8>加载当前SPI接口的Class getExtensionClasses(); //<12>处初始化 for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) { String name = entry.getKey(); Activate activate = entry.getValue(); //2个group做匹配 映证了@Activate的说法 if (isMatchGroup(group, activate.group())) { //根据spikey获取对应class实例 T ext = getExtension(name); //url传入的key不包含激活类配置 if (!names.contains(name) //因为-name表示移除 同时未移除 && !names.contains(Constants.REMOVE_VALUE_PREFIX + name) //如果配置了value 则必须在url判断是否有配置value激活 //比如配置@Activate("limit") n那么url必须传入limit=* && isActive(activate, url)) { exts.add(ext); } } } //根据@Activate配置的sort排序 Collections.sort(exts, ActivateComparator.COMPARATOR); } List<T> usrs = new ArrayList<T>(); //加载用户要激活的 for (int i = 0; i < names.size(); i++) { String name = names.get(i); //不加载-name的 因为表示剔除 上面默认配置也不会加载 if (!name.startsWith(Constants.REMOVE_VALUE_PREFIX) && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)) { /// 将配置的自定义在自动激活的拓展对象们前面。例如,<dubbo:service filter="demo,default,demo2" /> ,则 DemoFilter 就会放在默认的过滤器前面。i if (Constants.DEFAULT_KEY.equals(name)) { if (!usrs.isEmpty()) { exts.addAll(0, usrs); usrs.clear(); } } else { //获取扩展对象 T ext = getExtension(name); usrs.add(ext); } } } if (!usrs.isEmpty()) { exts.addAll(usrs); } return exts; }
<18>getExtension
@SuppressWarnings("unchecked") public T getExtension(String name) { if (name == null || name.length() == 0) throw new IllegalArgumentException("Extension name == null"); //如果配置的true则返回默认配置key即@SPI("dubbo")则返回dubbo if ("true".equals(name)) { return getDefaultExtension(); } //从缓存获取 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) { //<19>获得指定name的SPI实现类 instance = createExtension(name); holder.set(instance); } } } return (T) instance; }
<19>createExtension
@SuppressWarnings("unchecked") private T createExtension(String name) { //根据key获取SPI的配置的value Class<?> clazz = getExtensionClasses().get(name); if (clazz == null) { throw findException(name); } try { //获取对应class 的缓存实例对象 T instance = (T) EXTENSION_INSTANCES.get(clazz); if (instance == null) { EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance()); instance = (T) EXTENSION_INSTANCES.get(clazz); } //动态注入 injectExtension(instance); //获取wapper代理 <12> 处初始化 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); } }
<4>ExtensionFactory
类图
接口定义
@SPI public interface ExtensionFactory { /** * Get extension. * * @param type object type. * @param name object name. * @return object instance. */ <T> T getExtension(Class<T> type, String name); }
SPI配置
dubbo-common
resource/com.alibaba.dubbo.common.extension.ExtensionFactory
adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
SpringExtensionFactory
*/ public class SpringExtensionFactory implements ExtensionFactory { @Override @SuppressWarnings("unchecked") public <T> T getExtension(Class<T> type, String name) { //遍历spring 容器 根据beanName获取 for (ApplicationContext context : contexts) { //如果spring有这个bean直接返回 if (context.containsBean(name)) { Object bean = context.getBean(name); if (type.isInstance(bean)) { return (T) bean; } } } logger.warn("No spring extension (bean) named:" + name + ", try to find an extension (bean) of type " + type.getName()); //避免传入的是Object直接返回空 if (Object.class == type) { return null; } //根据根据BeanName未获取到 再根据Type获取 for (ApplicationContext context : contexts) { try { return context.getBean(type); } catch (NoUniqueBeanDefinitionException multiBeanExe) { logger.warn("Find more than 1 spring extensions (beans) of type " + type.getName() + ", will stop auto injection. Please make sure you have specified the concrete parameter type and there's only one extension of that type."); } catch (NoSuchBeanDefinitionException noBeanExe) { if (logger.isDebugEnabled()) { logger.debug("Error when get spring extension(bean) for type:" + type.getName(), noBeanExe); } } } logger.warn("No spring extension (bean) named:" + name + ", type:" + type.getName() + " found, stop get bean."); return null; } }
SpiExtensionFactory
/** * SpiExtensionFactory */ public class SpiExtensionFactory implements ExtensionFactory { @Override public <T> T getExtension(Class<T> type, String name) { //必须是接口类型 同时打上了@SPI注解 if (type.isInterface() && type.isAnnotationPresent(SPI.class)) { //<3> ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type); //<6>如果含有SPI注解 if (!loader.getSupportedExtensions().isEmpty()) { //<5> return loader.getAdaptiveExtension(); } } return null; } }
AdaptiveExtensionFactory
/** * AdaptiveExtensionFactory * 打了@Adaptive注解是一个手动装饰类 */ @Adaptive public class AdaptiveExtensionFactory implements ExtensionFactory { private final List<ExtensionFactory> factories; public AdaptiveExtensionFactory() { //加载 spi配置的ExtensionFactory配置实现 ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class); List<ExtensionFactory> list = new ArrayList<ExtensionFactory>(); for (String name : loader.getSupportedExtensions()) { list.add(loader.getExtension(name)); } //保存在spi成员变量 factories = Collections.unmodifiableList(list); } @Override public <T> T getExtension(Class<T> type, String name) { for (ExtensionFactory factory : factories) { //动态适配前面2种工厂 创建对象 T extension = factory.getExtension(type, name); if (extension != null) { return extension; } } return null; } }
<1>@Adaptive类例子
打在实现类上的实现
spi接口
@SPI public interface ExtensionFactory { /** * Get extension. * * @param type object type. * @param name object name. * @return object instance. */ <T> T getExtension(Class<T> type, String name); }
作用就是我们手动生成装饰类而不是利用javasist动态生成
@Adaptive public class AdaptiveExtensionFactory implements ExtensionFactory { private final List<ExtensionFactory> factories; public AdaptiveExtensionFactory() { //加载 spi配置的ExtensionFactory配置实现 ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class); List<ExtensionFactory> list = new ArrayList<ExtensionFactory>(); for (String name : loader.getSupportedExtensions()) { list.add(loader.getExtension(name)); } //保存在spi成员变量 factories = Collections.unmodifiableList(list); } @Override public <T> T getExtension(Class<T> type, String name) { for (ExtensionFactory factory : factories) { //动态适配前面2种工厂选择其中一个 T extension = factory.getExtension(type, name); if (extension != null) { return extension; } } return null; } }
打在接口方法上生成的代理
@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(); }
package com.alibaba.dubbo.rpc; import com.alibaba.dubbo.common.extension.ExtensionLoader; public class Protocol$Adpative 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.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.Invoker { 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); } public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws java.lang.Class { 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); } }
@SPI("javassist") public interface ProxyFactory { /** * create proxy. * * @param invoker * @return proxy */ @Adaptive({Constants.PROXY_KEY}) <T> T getProxy(Invoker<T> invoker) throws RpcException; /** * create proxy. * * @param invoker * @return proxy */ @Adaptive({Constants.PROXY_KEY}) <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException; /** * create invoker. * * @param <T> * @param proxy * @param type * @param url * @return invoker */ @Adaptive({Constants.PROXY_KEY}) <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException; }
package com.alibaba.dubbo.rpc; import com.alibaba.dubbo.common.extension.ExtensionLoader; public class ProxyFactory$Adpative implements com.alibaba.dubbo.rpc.ProxyFactory { public java.lang.Object getProxy(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.Invoker { 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.getParameter("proxy", "javassist"); if (extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])"); com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName); return extension.getProxy(arg0); } public com.alibaba.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, com.alibaba.dubbo.common.URL arg2) throws java.lang.Object { if (arg2 == null) throw new IllegalArgumentException("url == null"); com.alibaba.dubbo.common.URL url = arg2; String extName = url.getParameter("proxy", "javassist"); if (extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])"); com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName); return extension.getInvoker(arg0, arg1, arg2); } }
总结
1.dubbo默认会从META-INF/dubbo/internal/ ,META-INF/dubbo/,META-INF/services/ 加载SPI扩展文件
2.SPI扩展文件名字必须为SPI接口全名称
3.dubboSPI注入 会在反射获取SPI实例的set方法 获取方法名字 比如setAppliation 则会在spi和spring容器获取key="application"的spi实例
4.之所以会获取SPI和spring的实例是因为对象工厂的实现AdaptiveExtensionFactory 内部整合了2种容器