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的得到协议的名字
  • 通过指定名字的扩展点去获取相应的对象
  • 通过该对象去调用相应的方法

激活扩展点解析

回顾一下怎么使用:

测试类

相关文章

在网络请求时,总会有各种异常情况出现,我们需要提前处理这...
作者:宇曾背景软件技术的发展历史,从单体的应用,逐渐演进...
hello,大家好呀,我是小楼。最近一个技术群有同学at我,问我...
 一个软件开发人员,工作到了一定的年限(一般是3、4年左右...
当一个服务调用另一个远程服务出现错误时的外观Dubbo提供了多...
最近在看阿里开源RPC框架Dubbo的源码,顺带梳理了一下其中用...