1.SOFA RPC源码解析
1.1 扩展机制
1.1.1 简述
SOFA RPC的扩展点加载机制是从JDK标准的SPI扩展点发现机制加强而来。
SPI,全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制。
SPI是上游产商给服务供应商提供的接口,供应商遵循接口契约提供自己的实现。供应商提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里创建一个以服务接口命名的文件,该文件里就是实现该服务接口的具体实现类。当外部程序装配这个模块的时候,通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。
基于这样一个约定,可以很好的找到服务接口的实现类,而不需要再代码里制定。
Java SPI机制的约定和使用方法如下图所示:
Java SPI机制的约定:
1. 在META-INF/services/目录中创建以接口全限定名命名的文件该文件内容为API具体实现类的全限定名;
2. 使用ServiceLoader类动态加载META-INF中的实现类;
3. 如SPI的实现类为Jar,则需要放在主程序classPath中;
4. API具体实现类必须有一个不带参数的构造方法;
简单地了解了Java SPI服务扩展机制以后,我们再看看SOFA RPC的扩展点加载机制的类图:
SOFA RPC扩展机制的说明:
1. 定义接口或抽象类,并在类上增加@Extensible注解;
2. 定义接口或抽象类的具体实现类,并在类上增加@Extension注解;
3. 在META-INF/services/sofa-rpc目录中,创建以接口全限定名命名的文件,例如:com.alipay.sofa.rpc.module.Module。该文件内容为key-value键值对,key为实现类别名,value为API具体实现类的全限定名,例如:fault-tolerance=com.alipay.sofa.rpc.module.FaultToleranceModule;
4. 使用ExtensionLoaderFactory获取指定接口的ExtensionLoader实例,例如:ExtensionLoader<Module> loader = ExtensionLoaderFactory.getExtensionLoader(Module.class);
5. 通过ExtensionLoader类getExtension(Stringalias)方法动态加载META-INF中的实现类对应的实例,例如loader.getAllExtensions(“fault-tolerance”);
6. 如具体实现类为Jar,则需要放在主程序classPath中;
7. API具体实现类必须有一个不带参数的构造方法;
1.1.2 源码解析
以加载模块接口Module的实现类为例,详细说明RPC中的扩展机制。
1. ExtensionLoader<Module> loader =ExtensionLoaderFactory.getExtensionLoader(Module.class);
2. loader.getAllExtensions();
从上述代码可以看出,使用RPC扩展机制获取指定接口的具体实现类,主要包括两大步骤:
一、 获取指定接口对应的ExtensionLoader
从ExtensionLoaderFactory开始,该类是ExtensionLoader的工厂类,负责根据接口名称获取指定接口对应的ExtensionLoader。
1. public static <T>ExtensionLoader<T> getExtensionLoader(Class<T> clazz,ExtensionLoaderListener<T> listener) {
2. ExtensionLoader<T> loader =LOADER_MAP.get(clazz);
3. if (loader == null) {
4. synchronized (ExtensionLoaderFactory.class){
5. loader = LOADER_MAP.get(clazz);
6. if (loader == null) {
7. loader = new ExtensionLoader<T>(clazz,listener);
8. LOADER_MAP.put(clazz,loader);
9. }
10. }
11. }
12. return loader;
13. }
getExtensionLoader方法涉及的主要变量描述:
1. listener:ExtensionLoaderListener接口的实现类,当扩展点加载时,可以做一些额外处理工作,例如解析code,初始化等操作;
2. clazz:含有@Extensible注解的接口;
3. LOADER_MAP:全局变量,缓存已经加载的指定接口的ExtensionLoader;
首先,从LOADER_MAP获取指定接口的ExtensionLoader。如果存在,直接返回获取到的指定接口的ExtensionLoader;否则,创建新的ExtensionLoader;
1. public ExtensionLoader(Class<T>interfaceClass, ExtensionLoaderListener<T> listener) {
2. this(interfaceClass, true, listener);
3. }
调用ExtensionLoader的构造函数: