Dubbo扩展点SPI的源码分析

Dubbo扩展点SPI的源码分析

SPI描述和使用

简介: 读取META-INF/dubbo/internal/,META-INF/dubbo/,META-INF/services/文件夹下的文件,文件名:就是要加载的类名,文件内容以key=value形式储存,value是加载类的实现类和包装类,key为value的标识。怎么识别是不是包装类呢?包装类的构建方法是有参的,该参数是要加载的对象。实现类是无参构建的。SPI的有三钟方式进行使用

  • 指定名字的扩展点
  • 自适应扩展点
  • 激活扩展点

指定名字的扩展点

描述: 传入要加载的类和名字就能得到加载类的实现类

使用方式:

ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("dubbo")

自适应扩展点

​ 描述: 只需要传入类名,通过自适应的方式去获取。 如果实现的类名上加了@Adaptive,那么默认返回的就是改实现类对象,如果都没加上的话,以Protocol为例,他会生成一个Protocol$Adaptive,Protocol$Adaptive.export()方法大体是:通过传进来Invoker,得到了URL,因此也能得到相应的协议的名字,然后再通过改名字,去通过指定名字的扩展点去获取实现类,实现类去调用export()。其他方法也是差不多大概的逻辑

使用方式:

ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension()

激活扩展点

相当于Spring中的conditional

使用方法:

        URL url = new URL("dubbo", "", 0);
        url = url.addParameter("cache","A");
        url = url.addParameter("cacheA","ABC");
		//返回的是B
        List<InterfaceService> activateExtension = ExtensionLoader.getExtensionLoader(InterfaceService.class).getActivateExtension(url,"cache1");
        System.err.println(activateExtension);

	//返回的是A和B
        List<InterfaceService> activateExtension1 = ExtensionLoader.getExtensionLoader(InterfaceService.class).getActivateExtension(url,"cache");
        System.err.println(activateExtension1);

InterfaceService类型:

@Activate(value = "ABC")
public class AService implements InterfaceService{
}
@Activate(value = "cacheA:ABC")//这里是需要key:value形式的
public class BService implements  InterfaceService {
}
public class CService implements  InterfaceService {
}

META-INF/dubbo/internal/com.onion.service.InterfaceService文件:

A=com.onion.service.AService
B=com.onion.service.BService
C=com.onion.service.CService

注意:

  • 不带@Activate注解是无法加载到的
  • @Activate里面的value和group为null的时候,代表默认会加载返回
  • getActivateExtension(url,"cache") 方法中里key是cache,如果跟 url = url.addParameter("cache","A");中也存在cache,那么A一定要有存在于META-INF/dubbo/internal/com.onion.service.InterfaceService文件中的key里,如果没有的话就会报错 ----- 因为代码会通过指定名字扩展点去获取A,如果获取不倒就会报错的。
  • @Activate的value的形式要按照:key:value来,不然就会匹配不上的
  • @Activate里value值是key:value形式的数组,url参数是key=value,然后对比各自的key和value,如果匹配上就能匹配上返回

ExtensionLoader一些成员变量的说明

 //针对于指定名字扩展点的,key为指定的名字,value为指定名字的对象
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap();  

 //key为指定的名字,value为指定名字的类,-->赋值的在:loadclass的时候就会把他保存起来
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder();

//key为类名,value为对象名。
private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap(64);、
    
//自适应扩展点中,如果实现类带有@Adaptive就会缓存起来,-->赋值的在:loadclass的时候就会把他保存起来
private volatile Class<?> cachedAdaptiveClass = null;
    
//包装类集合: -->赋值的在:loadclass的时候就会把他保存起来
private Set<Class<?>> cachedWrapperClasses;

//保存ExtensionLoader.getExtensionLoader(type)中的type
private final Class<?> type;

//存储自适应扩展点新增出来的对象
private final Holder<Object> cachedAdaptiveInstance = new Holder();


//带有@Activate注解的实现类  -->赋值的在:loadclass的时候就会把他保存起来
private final Map<String, Object> cachedActivates = new ConcurrentHashMap();

ExtensionLoader.getExtensionLoader 解析

ExtensionLoader类中:

private final Class<?> type;
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap(64);


public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        //type问题的异常处理
        if (type == null) {
            throw new IllegalArgumentException("Extension type == null");
        } else if (!type.isInterface()) {
            throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
        } else if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type (" + type + ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
        } else {
            ExtensionLoader<T> loader = (ExtensionLoader)EXTENSION_LOADERS.get(type);
            if (loader == null) {
                EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type)); //新建一个ExtensionLoader返回
                loader = (ExtensionLoader)EXTENSION_LOADERS.get(type);
            }

            return loader;
        }
    }


   private ExtensionLoader(Class<?> type) {
        this.type = type;   //会保存存进来的类放到type里面。
        this.objectFactory = type == ExtensionFactory.class ? null : (ExtensionFactory)getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension();       //this.objectFactory就
    }

​ getExtensionLoader功能介绍:保存type,如果type不是ExtensionFactory情况下,objectFactory其实就是AdaptiveExtensionFactory,因为AdaptiveExtensionFactory带了@Adaptive,objectFactory用途就是依赖注入的时候用来创建相应的对象的。

AdaptiveExtensionFactory作用:遍历其他的实现类,看下哪个可以实现类可以去创建依赖注入对象,相当于是一个管理ExtensionFactory的管理员

其中有个两个比较重要的实现类:

  • SpiExtensionFactory:通过自适应扩展点去新建
  • SpringExtensionFactory:通过spirng容器里看下有没有这个对象有就返回

image-20201027152628030

指定名字的扩展点解析

ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName)

ExtensionLoader方法中:

 public T getExtension(String name) {
        return this.getExtension(name, true);
    }

public T getExtension(String name, boolean wrap) {
    if (StringUtils.isEmpty(name)) {
        throw new IllegalArgumentException("Extension name == null");
    } else if ("true".equals(name)) {
        return this.getDefaultExtension();
    } else {
        //通过名字拿到holder
        Holder<Object> holder = this.getOrCreateHolder(name);
        Object instance = holder.get();
        //instance为空则新增一个,并且放到holder里
        if (instance == null) {
            synchronized(holder) {
                instance = holder.get();
                if (instance == null) {
                    instance = this.createExtension(name, wrap);
                    holder.set(instance);
                }
            }
        }
        return instance;
    }
}


//通过名字读取缓存,如果有则返回,没有则新建一个 new Holder()返回
  private Holder<Object> getOrCreateHolder(String name) {
        Holder<Object> holder = (Holder)this.cachedInstances.get(name);
        if (holder == null) {
            this.cachedInstances.putIfAbsent(name, new Holder());
            holder = (Holder)this.cachedInstances.get(name);
        }

        return holder;
}

//通过名字创建一个instance
 private T createExtension(String name, boolean wrap) {
     //通过名字查看有没有缓存下来的类。
        Class<?> clazz = (Class)this.getExtensionClasses().get(name);
        if (clazz == null) {
            throw this.findException(name);
        } else {
            try {
                //通过类名查看有没有缓存下来的对象
                T instance = EXTENSION_INSTANCES.get(clazz);
                if (instance == null) {
                    //通过反射新建一个对象
                    EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                    instance = EXTENSION_INSTANCES.get(clazz);
                }
				//依赖注入成员变量
                this.injectExtension(instance);
                if (wrap) {
         			....包装instance,下面有详细介绍...
                }

                this.initExtension(instance);
                return instance;
            } catch (Throwable var9) {
                throw new IllegalStateException("Extension instance (name: " + name + ", class: " + this.type + ") couldn't be instantiated: " + var9.getMessage(), var9);
            }
        }
    }


    private Map<String, Class<?>> getExtensionClasses() {
        Map<String, Class<?>> classes = (Map)this.cachedClasses.get();
        if (classes == null) {
            synchronized(this.cachedClasses) {
                classes = (Map)this.cachedClasses.get();
                if (classes == null) {
                    classes = this.loadExtensionClasses();
                    this.cachedClasses.set(classes);
                }
            }
        }

        return classes;
    }


    private Map<String, Class<?>> loadExtensionClasses() {
        this.cacheDefaultExtensionName();
        Map<String, Class<?>> extensionClasses = new HashMap();
        LoadingStrategy[] var2 = strategies;
        int var3 = var2.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            LoadingStrategy strategy = var2[var4];
            this.loadDirectory(extensionClasses, strategy.directory(), this.type.getName(), 
                               strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
            this.loadDirectory(extensionClasses, strategy.directory(), this.type.getName().replace("org.apache", "com.alibaba"), 
                               strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
        }

        return extensionClasses;
    }

getExtension方法是: 利用指定的名字,看下有没有缓存的对象(getOrCzhreateHolder方法实现),有的话直接返回,没有则创建(createExtension方法实现)。

  • getOrCreateHolder: 从cachedInstances中获取key为指定的名字的缓存对象,如果没有则新建一个holder

  • createExtension:

    • 首先调用getExtensionClasses()方法去拿取缓存的类名集合Map信息

      • 没有则调用loadExtensionClasses(下面会解析)去读取文件把类名加载上来
    • 得到类名集合后,通过传进来的name得到相应的类名

    • 通过EXTENSION_INSTANCES查看有没有key为类名,value为对象的缓存

    • clazz.newInstance() 新建对象一个对象

    • this.injectExtension(instance); 依赖注入对象中成员变量

    • 如果有包装类,把instance包装成包装类对象返回

总结:其实整体步骤就是看下通过指定的名字,看下有没有缓存下来的对象,没有则看下有没有缓存起来的类名信息集合Map,没有则读取相应文件,然后得到名字对应的类名,接着通过反射来新建对象,然后再依赖注入该对象的成员变量,如果有包装类则用包装类包装该对象返回

loadExtensionClasses读取文件加载类名到内存中

ExtensionLoader类名:

private static volatile LoadingStrategy[] strategies = loadLoadingStrategies();


private static LoadingStrategy[] loadLoadingStrategies() {
    //通过java的spi来获取
        return (LoadingStrategy[])StreamSupport.stream(ServiceLoader.load(LoadingStrategy.class).spliterator(), false).sorted().toArray((x$0) -> {
            return new LoadingStrategy[x$0];
        });
 }


private Map<String, Class<?>> loadExtensionClasses() {
        this.cacheDefaultExtensionName();
        Map<String, Class<?>> extensionClasses = new HashMap();
        LoadingStrategy[] var2 = strategies;
        int var3 = var2.length;

    	//遍历读取文件夹,文件夹有:`META-INF/dubbo/internal/`,`META-INF/dubbo/`,`META-INF/services/`
        for(int var4 = 0; var4 < var3; ++var4) {
            LoadingStrategy strategy = var2[var4];
            this.loadDirectory(extensionClasses, strategy.directory(), this.type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
            this.loadDirectory(extensionClasses, strategy.directory(), this.type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
        }
        return extensionClasses;
}


    
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type, boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) {
    //文件名就是目录名加类名
        String fileName = dir + type;

        try {
            Enumeration<java.net.URL> urls = null;
            ClassLoader classLoader = findClassLoader();
            
            //一系列手段去加载文件名得到url,
            //ExtensionLoader.class.getClassLoader().getResources(fileName)
            //classLoader.getResources(fileName)和ClassLoader.getSystemResources(fileName);
         		....

            if (urls != null) {
                while(urls.hasMoreElements()) {
                    java.net.URL resourceURL = (java.net.URL)urls.nextElement();
                    //读取文件资源
                    this.loadResource(extensionClasses, classLoader, resourceURL, overridden, excludedPackages);
                }
            }
        } catch (Throwable var11) {
            logger.error("Exception occurred when loading extension class (interface: " + type + ", description file: " + fileName + ").", var11);
        }

    }

    
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL, boolean overridden, String... excludedPackages) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8));
            Throwable var7 = null;

            try {
                String line;
                try {
                    //读取文件的每一行,因为一行代表一个父类
                    while((line = reader.readLine()) != null) {
                        int ci = line.indexOf(35);
                        if (ci >= 0) {
                            line = line.substring(0, ci);
                        }

                        line = line.trim();
                        ...一行格式是: name=className,这部分代码就是把name和className解析出来 ...
                            //读取类信息
           				this.loadClass(extensionClasses, resourceURL, 
                                       Class.forName(line, true, classLoader), name, overridden);
                        ...

                    }
                } catch (Throwable var22) {
               		...
                }
            } finally {
             	...
            }
        } catch (Throwable var24) {
			....
        }

    }

  

这里首先我们先看下strategies的来历先,strategies是通过java的spi加载进来了,得到一个数组,数组成员有:

  • DubboInternalLoadingStrategy:this.directory()返回的是:"META-INF/dubbo/internal/"
  • DubboLoadingStrategy: this.directory()返回的是:"META-INF/dubbo/"
  • ServicesLoadingStrategy: this.directory()返回的是:"META-INF/services/"

所以我们读取的文件夹有META-INF/dubbo/internal/,META-INF/dubbo/,META-INF/services/

言归正转分析loadExtensionClasses方法:

  • 遍历strategies相应的文件夹,读取相应的文件(loadDirectory读取文件方法)
  • loadDirectory方法:通过传进来的文件夹和类名拼接成路径字符串,然后再用类加载器去得到URL,然后调用loadResource方法去读取文件资源
  • loadResource方法:读取文件中的每一行,然后再通过loadClass去加载类。

dubbo的sqi文件格式如下:

image-20201027163653655

loadClass加载类分析

ExtensionLoader类名:

private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name, boolean overridden) throws NoSuchMethodException {
        if (!this.type.isAssignableFrom(clazz)) {
            throw new IllegalStateException("Error occurred when loading extension class (interface: " + this.type + ", class line: " + clazz.getName() + "), class " + clazz.getName() + " is not subtype of interface.");
        } else {
            if (clazz.isAnnotationPresent(Adaptive.class)) {  //如果是类名带上@Adaptive,cachedAdaptiveClass=clazz
                this.cacheAdaptiveClass(clazz, overridden);
            } else if (this.isWrapperClass(clazz)) {//如果是包装类,放进包装类集合
                this.cacheWrapperClass(clazz);    
            } else {
                //确定能无参构造,确认不是包装类
                clazz.getConstructor();
				...name是空的情况下的处理...
                    
                //按照,分割
                String[] names = NAME_SEPARATOR.split(name);
                if (ArrayUtils.isNotEmpty(names)) {
                    this.cacheActivateClass(clazz, names[0]);
                    String[] var7 = names;
                    int var8 = names.length;
                    for(int var9 = 0; var9 < var8; ++var9) {
                        String n = var7[var9];
                        this.cacheName(clazz, n);
                        //把名字和类名put进extensionClasses
                        this.saveInExtensionClass(extensionClasses, clazz, n, overridden);
                    }
                }
            }

        }
    }


	//overridden是否要覆盖
    private void cacheAdaptiveClass(Class<?> clazz, boolean overridden) {
        ...overridden为false且原本就有cachedAdaptiveClass,就报错(一个接口不能有两个贷有Adaptive的实现类)...
 
        this.cachedAdaptiveClass = clazz; //缓存cachedAdaptiveClass,这个就是自适应中的那个类

    }

//判断是否包装类,如果构造方法是有参的认为是包装类
    private boolean isWrapperClass(Class<?> clazz) {
        try {
            clazz.getConstructor(this.type);
            return true;
        } catch (NoSuchMethodException var3) {
            return false;
        }
    }

   private void cacheWrapperClass(Class<?> clazz) {
        if (this.cachedWrapperClasses == null) {
            this.cachedWrapperClasses = new ConcurrentHashSet();
        }

        this.cachedWrapperClasses.add(clazz);   //放进包装类集合
   }

    private void saveInExtensionClass(Map<String, Class<?>> extensionClasses, Class<?> clazz, String name, boolean overridden) {
        ...overridden为false且原本就有值,就报错...
            //把名字和类名put进extensionClasses
		 extensionClasses.put(name, clazz);
    }


//把带有Activate注解的放进cachedActivates中
  private void cacheActivateClass(Class<?> clazz, String name) {
        Activate activate = (Activate)clazz.getAnnotation(Activate.class);
        if (activate != null) {
            this.cachedActivates.put(name, activate);
        } else {
            com.alibaba.dubbo.common.extension.Activate oldActivate = (com.alibaba.dubbo.common.extension.Activate)clazz.getAnnotation(com.alibaba.dubbo.common.extension.Activate.class);
            if (oldActivate != null) {
                this.cachedActivates.put(name, oldActivate);
            }
        }

    }

loadClass流程:

  • 如果类名上带有@Adaptive,存到this.cachedAdaptiveClass里面

  • 如果类是包装类,存到this.cachedWrapperClasses Map集合里面

  • 剩下的情况:

    • 把带有Activate注解的放进this.cachedActivates中。
    • 并且把实现类存到extensionClasses里面,最后返回到上层,上层会调用 this.cachedClasses.set(classes);存储起来,所以最终是存到cachedClasses方法里

injectExtension依赖注入对象

	//instance依赖注入的实现
    private T injectExtension(T instance) {
        if (this.objectFactory == null) {
            return instance;
        } else {
            try {
                //获取对象的所有方法
                Method[] var2 = instance.getClass().getMethods();
                int var3 = var2.length;

                for(int var4 = 0; var4 < var3; ++var4) {
                    Method method = var2[var4];
                    //判读是否是否是以set开头的方法,且方法头上没带DisableInject
                    if (this.isSetter(method) && method.getAnnotation(DisableInject.class) == null) {
                        Class<?> pt = method.getParameterTypes()[0];
                        if (!ReflectUtils.isPrimitives(pt)) {
                            try {
                                String property = this.getSetterProperty(method);
                                //新建一个依赖注入的对象,pt是类名(入参第一个的类型),property指定扩展点的名字(由setXXX方法名分析而来)
                                Object object = this.objectFactory.getExtension(pt, property);
                                if (object != null) {
                                    //给intancez注入新建的object
                                    method.invoke(instance, object);
                                }
                            } catch (Exception var9) {
                                logger.error("Failed to inject via method " + method.getName() + " of interface " + this.type.getName() + ": " + var9.getMessage(), var9);
                            }
                        }
                    }
                }
            } catch (Exception var10) {
                logger.error(var10.getMessage(), var10);
            }

            return instance;
        }
    }

    private boolean isSetter(Method method) {
        return method.getName().startsWith("set") && method.getParameterTypes().length == 1 && Modifier.isPublic(method.getModifiers());
    }

    private String getSetterProperty(Method method) {
        return method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
    }

依赖注入实现的流程:

  • 获取传进来对象得所有方法并且找到set开头的方法,且方法头上没带DisableInject

  • 通过objectFactory.getExtension去创建一个对象

    • objectFactory是一个ExtensionFactory,里面是AdaptiveExtensionFactor。创建位置可以看ExtensionLoader.getExtensionLoader部分

    • AdaptiveExtensionFactory.getExtension:遍历所有ExtensionFactory得实现类,然后再一个个的去尝试getExtension。其中有SpiExtensionFactorySpringExtensionFactory

      • SpiExtensionFactory:通过自适应扩展点去新建
      • SpringExtensionFactory:通过spirng容器里看下有没有这个对象有就返回

image-20201027152628030

instance包装成包装类对象返回

这里重新看看createExtension,创建了instance并且依赖注入后,后面的逻辑

 private T createExtension(String name, boolean wrap) {
  			...
    //通过类名查看有没有缓存下来的对象
   	T instance = EXTENSION_INSTANCES.get(clazz);
     if (instance == null) {
         //通过反射新建一个对象
         EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
         instance = EXTENSION_INSTANCES.get(clazz);
     }
     //依赖注入成员变量
     this.injectExtension(instance);
     if (wrap) {
         List<Class<?>> wrapperClassesList = new ArrayList();
         //把this.cachedWrapperClasses包装类放到wrapperClassesList中并排序
         if (this.cachedWrapperClasses != null) {
             wrapperClassesList.addAll(this.cachedWrapperClasses);
             wrapperClassesList.sort(WrapperComparator.COMPARATOR);
             Collections.reverse(wrapperClassesList);
         }

         if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
             Iterator var6 = wrapperClassesList.iterator();
             label37:
             //遍历包装类一层层的新建包装类,
             while(true) {
                 Class wrapperClass;
                 Wrapper wrapper;
                 do {
                     if (!var6.hasNext()) {
                         break label37;
                     }
                     wrapperClass = (Class)var6.next();
                     wrapper = (Wrapper)wrapperClass.getAnnotation(Wrapper.class);
                 } while(wrapper != null && (!ArrayUtils.contains(wrapper.matches(), name) || ArrayUtils.contains(wrapper.mismatches(), name)));

                 //新建包装类,把instance作为构造参数传入,让instance等于包装类
                 instance = this.injectExtension(wrapperClass.getConstructor(this.type).newInstance(instance));
             }
         }
     }

     this.initExtension(instance);
     return instance;

}

 private void initExtension(T instance) {
        if (instance instanceof Lifecycle) {
            Lifecycle lifecycle = (Lifecycle)instance;
            lifecycle.initialize();
        }

 }


包装的过程:

  • 把this.cachedWrapperClasses包装类集合按照相应的顺序,放到wrapperClassesList集合中
  • 遍历包装类,并且一层层的包装
  • 如果返回的类是Lifecycle,则调用initialize(),进行初始化

自适应扩展点解析

自定义扩展点的使用

ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension()

这里直接分析ExtensionLoader中的getAdaptiveExtension:

 private final Holder<Object> cachedAdaptiveInstance = new Holder();
   
public T getAdaptiveExtension() {
        Object instance = this.cachedAdaptiveInstance.get();
        if (instance == null) {
         	...
            synchronized(this.cachedAdaptiveInstance) {
                instance = this.cachedAdaptiveInstance.get();
                if (instance == null) {
                    try {
                        instance = this.createAdaptiveExtension();
                        this.cachedAdaptiveInstance.set(instance);
                    } catch (Throwable var5) {
                        this.createAdaptiveInstanceError = var5;
                        throw new IllegalStateException("Failed to create adaptive instance: " + var5.toString(), var5);
                    }
                }
            }
        }

        return instance;
    }

    private T createAdaptiveExtension() {
        try {
            return this.injectExtension(this.getAdaptiveExtensionClass().newInstance());
        } catch (Exception var2) {
            throw new IllegalStateException("Can't create adaptive extension " + this.type + ", cause: " + var2.getMessage(), var2);
        }
    }

   private Class<?> getAdaptiveExtensionClass() {
        this.getExtensionClasses();
        return this.cachedAdaptiveClass != null ? this.cachedAdaptiveClass : (this.cachedAdaptiveClass = this.createAdaptiveExtensionClass());
    }

  private Class<?> createAdaptiveExtensionClass() {
        String code = (new AdaptiveClassCodeGenerator(this.type, this.cachedDefaultName)).generate();
        ClassLoader classLoader = findClassLoader();
        Compiler compiler = (Compiler)getExtensionLoader(Compiler.class).getAdaptiveExtension();
        return compiler.compile(code, classLoader);
    }

上面的代码如下步骤:

  • 判断缓冲中有没有自定义扩展点的对象,有则取出

  • 执行这些步骤createAdaptiveExtension ->createAdaptiveExtension(获取相应的类返回)

    • 首先调用getExtensionClasses()方法去拿取缓存的类名集合Map信息

      • 没有则调用loadExtensionClasses去读取文件把类名加载上来,这里指定名字的扩展点有解析
    • createAdaptiveExtensionClass (从名字可以看到创建自适应扩展类)

      • 判断cachedAdaptiveClass是否是空 ,不为空直接返回, cachedAdaptiveClass这个的赋值位置在(指定名字扩展点源码分析的)ExtensionLoader.loadClass中,作用大概就是:判断读取过来的实现类是否带有@Adaptive,是的话赋值到cachedAdaptiveClass中
      • cachedAdaptiveClass是空的话,利用generate()方法把类创建成一个字符串。然后得到相应的编译器,编辑成类返回
  • this.injectExtension(this.getAdaptiveExtensionClass().newInstance()) 返回getAdaptiveExtensionClass的类再通过放射新建,然后再使用依赖注入相应的成员便利。依赖注入前面也有说到

  • 最后返回相应的对象,再把这个对象存到cachedAdaptiveInstance里面

拼接一个XXX$Adaptive的实现类

AdaptiveClassCodeGenerator类中的部分代码

public class AdaptiveClassCodeGenerator {
    private static final Logger logger = LoggerFactory.getLogger(AdaptiveClassCodeGenerator.class);
    private static final String CLASSNAME_INVOCATION = "org.apache.dubbo.rpc.Invocation";
    private static final String CODE_PACKAGE = "package %s;\n";
    private static final String CODE_IMPORTS = "import %s;\n";
		....
    public String generate() {
                //遍历类的所有方法看下方法上是不是带有@Adaptive注解
        if (!this.hasAdaptiveMethod()) {
            throw new IllegalStateException("No adaptive method exist on extension " + this.type.getName() + ", refuse to create the adaptive class!");
        } else {
            StringBuilder code = new StringBuilder();
            code.append(this.generatePackageInfo());
            code.append(this.generateImports());
            code.append(this.generateClassDeclaration());
            Method[] methods = this.type.getMethods();
            Method[] var3 = methods;
            int var4 = methods.length;

            for(int var5 = 0; var5 < var4; ++var5) {
                Method method = var3[var5];
                code.append(this.generateMethod(method));
            }

            code.append("}");
            if (logger.isDebugEnabled()) {
                logger.debug(code.toString());
            }

            return code.toString();
        }
    }
	private String generatePackageInfo() {
        return String.format("package %s;\n", this.type.getPackage().getName());
    }
    
    //遍历类的所有方法看下方法上是不是带有@Adaptive注解
     private boolean hasAdaptiveMethod() {
        return Arrays.stream(this.type.getMethods()).anyMatch((m) -> {
            return m.isAnnotationPresent(Adaptive.class);
        });
    }
}

可以看到首先要先看下类的方法上是否带了@Adaptive注解 ,有的话会把一个类文件的内容拼接成字符串返回。

如果是ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension()最后生成的类如下:

package org.apache.dubbo.rpc;
import org.apache.dubbo.common.extension.ExtensionLoader;


public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
    public void destroy()  {
        throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }
    public int getDefaultPort()  {
        throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }
    public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
        if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
        if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
        //从Invoker中获取URL
        org.apache.dubbo.common.URL url = arg0.getUrl();
        //如果为空则返回dubbo协议,然后再通过名字的扩展点,找到相应的protocol对象
        String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
        if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        //调用指定名字扩展点得到的对象进行方法调用
        return extension.export(arg0);
    }
    public java.util.List getServers()  {
        throw new UnsupportedOperationException("The method public default java.util.List org.apache.dubbo.rpc.Protocol.getServers() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }
    public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        org.apache.dubbo.common.URL url = arg1;
        String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
        if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }
}

可以看到最后生成的类其实就是:

  • 通过传进来的Invoker,得到相应的URL
  • 通过URL的得到协议的名字
  • 通过指定名字的扩展点去获取相应的对象
  • 通过该对象去调用相应的方法

激活扩展点解析

回顾一下怎么使用:

测试类🐶

URL url = new URL("dubbo", "", 0);
url = url.addParameter("cache","A");
List<InterfaceService> activateExtension = ExtensionLoader.getExtensionLoader(InterfaceService.class).getActivateExtension(url,"cache");
System.err.println(activateExtension);

InterfaceService类型:

@Activate(value = "ABC")
public class AService implements InterfaceService{
}
@Activate(value = "cache:A")  //这里是需要key:value形式的
public class BService implements  InterfaceService {
}
public class CService implements  InterfaceService {
}

META-INF/dubbo/internal/com.onion.service.InterfaceService文件:

A=com.onion.service.AService
B=com.onion.service.BService
C=com.onion.service.CService

源码解析,这里直接分析ExtensionLoader中的getActivateExtension:

  public List<T> getActivateExtension(URL url, String key) {
      //此时的gourp为空
        return this.getActivateExtension(url, (String)key, (String)null);
    }


    public List<T> getActivateExtension(URL url, String key, String group) {
        //通过传进来的key获取url中的相应的参数值
        String value = url.getParameter(key);
        return this.getActivateExtension(url, StringUtils.isEmpty(value) ? null : CommonConstants.COMMA_SPLIT_PATTERN.split(value), group);
    }

 public List<T> getActivateExtension(URL url, String[] values, String group) {
        List<T> activateExtensions = new ArrayList();
     	//url中的相应的参数值
        List<String> names = values == null ? new ArrayList(0) : Arrays.asList(values);
        String name;
        if (!((List)names).contains("-default")) {
            //加载文件里面的类信息
            this.getExtensionClasses();
            //cachedActivates是带有@Activate注解的实现类 ,在loadclass的时候加入到cachedActivates中去,详情请看loadclass方法解析
            Iterator var6 = this.cachedActivates.entrySet().iterator();

            label59:
            while(true) {
                String[] activateGroup;
                String[] activateValue;
                while(true) {
                    if (!var6.hasNext()) {
                        activateExtensions.sort(ActivateComparator.COMPARATOR);
                        break label59;
                    }

                    Entry<String, Object> entry = (Entry)var6.next();
                    name = (String)entry.getKey();
                    Object activate = entry.getValue();
                    if (activate instanceof Activate) {
                        activateGroup = ((Activate)activate).group();
                        activateValue = ((Activate)activate).value();
                        break;
                    }

                    
                    //为了兼容com.alibaba.dubbo.common.extension.Activate
                    if (activate instanceof com.alibaba.dubbo.common.extension.Activate) {
                        activateGroup = ((com.alibaba.dubbo.common.extension.Activate)activate).group();
                        activateValue = ((com.alibaba.dubbo.common.extension.Activate)activate).value();
                        break;
                    }
                }
                
                //name:META-INF/dubbo/internal/...文件里的key值
                //activateValue:@Activate里的value值
                //names:url相应参数的值
                
                //条件判断:
                //isMatchGroup:group的匹配
                //url参数不包含的value值不包含name值和("-"+name)值
                //isActive: url参数和@Activate的条件判断
                if (this.isMatchGroup(group, activateGroup) && !((List)names).contains(name) && !((List)names).contains("-" + name) && this.isActive(activateValue, url)) {
                    activateExtensions.add(this.getExtension(name));
                }
            }
        }

        List<T> loadedExtensions = new ArrayList();

     //遍历url相应参数的值,并把这些值通过指定名字字扩展点去获取
     //这就是为什么,没有名字在META-INF/dubbo/internal/...文件里的会报错的原因
        for(int i = 0; i < ((List)names).size(); ++i) {
            name = (String)((List)names).get(i);
            if (!name.startsWith("-") && !((List)names).contains("-" + name)) {
                if ("default".equals(name)) {
                    if (!loadedExtensions.isEmpty()) {
                        activateExtensions.addAll(0, loadedExtensions);
                        loadedExtensions.clear();
                    }
                } else {
                    //通过指定名字字扩展点去获取
                    loadedExtensions.add(this.getExtension(name));
                }
            }
        }

        if (!loadedExtensions.isEmpty()) {
            activateExtensions.addAll(loadedExtensions);
        }

        return activateExtensions;
    }


//url参数和@Activate的条件判断
//keys:@Activate里的value值
private boolean isActive(String[] keys, URL url) {
        if (keys.length == 0) {
            return true;
        } else {
            String[] var3 = keys;
            int var4 = keys.length;
            int var5 = 0;

            label44:
            while(var5 < var4) {
                String key = var3[var5];
                String keyValue = null;
                //这里就是为什么形式是:key:value的原因了
                if (key.contains(":")) {
                    String[] arr = key.split(":");
                    key = arr[0];
                    keyValue = arr[1];
                }

                //url的参数值
                Iterator var12 = url.getParameters().entrySet().iterator();

                String k;
                String v;
                do {
                    do {
                        if (!var12.hasNext()) {
                            ++var5;
                            continue label44;
                        }

                        Entry<String, String> entry = (Entry)var12.next();
                        k = (String)entry.getKey();
                        v = (String)entry.getValue();
                        //key的对比
                    } while(!k.equals(key) && !k.endsWith("." + key));
                    //value的对比
                } while((keyValue == null || !keyValue.equals(v)) && (keyValue != null || !ConfigUtils.isNotEmpty(v)));

                return true;
            }

            return false;
        }
    }
    
    
  • names: 通过传进来的key获取url中的相应的参数值 -----------getActivateExtension(url,key)这上面的key

  • this.getExtensionClasses()加载文件里面的类信息

  • 遍历this.cachedActivates(带有@Activate注解的实现类集合),得到@Activate注解中group,value的集合

  • 加入activateExtensions位置)条件判断看下是否要加入到activateExtensions返回,条件如下:

    • isMatchGroup:group的匹配

    • url里相应参数的value值不包含name值和("-"+name)值

    • isActive: url参数和@Activate里value的条件判断,@Activate里value值是key:value形式的数组,url参数是key=value,然后对比各自的key和value,如果匹配上就返回true

  • 加入activateExtensions位置)遍历names集合去this.getExtension(name)(通过指定名字的扩展点去获取对象),把该对象放入到activateExtensions

大概的流程图展示:

高清流程图下载:https://gitee.com/gzgyc/blogimage/raw/master/dubbo的spi流程图.jpg

posted @ 2020-11-07 16:52  大笨象会跳舞  阅读(124)  评论(0编辑  收藏  举报