JDK的SPI机制:
spi 的全称是 service provider interface, 它是jdk内置的一种服务提供发现机制。常用于框架设计中:运行时动态为接口提供实现。
SPI的使用
a.创建接口PrintService.java
package com.alibaba.dubbo.study.day02.javaspi;
/**
* @author 周宁
* @Date 2019-10-14 16:30
*/
public interface PrintService {
void printInfo();
}
b.提供实现类
PrintHelloWorldServiceImpl.java
package com.alibaba.dubbo.study.day02.javaspi;
/**
* @author 周宁
* @Date 2019-10-14 16:31
*/
public class PrintHelloWorldServiceImpl implements PrintService{
@Override
public void printInfo() {
System.out.println("hello world");
}
}
PrintNicServiceImpl.java
package com.alibaba.dubbo.study.day02.javaspi;
/**
* @author 周宁
* @Date 2019-10-14 16:35
*/
public class PrintNicServiceImpl implements PrintService{
@Override
public void printInfo() {
System.out.println("nic");
}
}
c.在resources文件夹下新建目录/META-INF/package com.alibaba.dubbo.study.day02.javaspi.PrintService文件并加入如下内容
com.alibaba.dubbo.study.day02.javaspi.PrintHelloWorldServiceImpl
com.alibaba.dubbo.study.day02.javaspi.PrintNicServiceImpl
d.写个测试类SPITest.java
package com.alibaba.dubbo.study.day02.javaspi;
import java.util.ServiceLoader;
/**
* @author 周宁
* @Date 2019-10-14 16:34
*/
public class SPITest {
public static void main(String[] args) {
ServiceLoader<PrintService> services = ServiceLoader.load(PrintService.class);
for(PrintService ps : services){
ps.printInfo();
}
}
}
应用场景:概括地说,适用于: 调用者根据实际使用需要,启用、扩展、或者替换框架的实现策略比较常见的例子:数据库驱动加载接口实现类的加载 JDBC加载不同类型数据库的驱动.日志门面接口实现类加载 SLF4J加载不同提供商的日志实现类
要使用Java SPI,需要遵循如下约定:
- 1、当服务提供者提供了接口的一种具体实现后,在jar包的META-INF/services目录下创建一个以“接口全限定名”为命名的文件,内容为实现类的全限定名;
- 2、接口实现类所在的jar包放在主程序的classpath中;
- 3、主程序通过java.util.ServiceLoder动态装载实现模块,它通过扫描META-INF/services目录下的配置文件找到实现类的全限定名,把类加载到JVM;
- 4、SPI的实现类必须携带一个不带参数的构造方法;
Dubbo的SPI机制:
Dubbo 的扩展点加载从 JDK 标准的 SPI (Service Provider Interface) 扩展点发现机制加强而来。
Dubbo 改进了 JDK 标准的 SPI 的以下问题:
- JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。
- 如果扩展点加载失败,连扩展点的名称都拿不到了。比如:JDK 标准的 ScriptEngine,通过
getName()
获取脚本类型的名称,但如果 RubyScriptEngine 因为所依赖的 jruby.jar 不存在,导致 RubyScriptEngine 类加载失败,这个失败原因被吃掉了,和 ruby 对应不起来,当用户执行 ruby 脚本时,会报不支持 ruby,而不是真正失败的原因。 - 把配置文件中扩展实现的格式修改,例如META-INF/dubbo/com.xxx.Protocol里的com.foo.XxxProtocol格式改为了xxx = com.foo.XxxProtocol这种以键值对的形式,这样做的目的是为了让我们更容易的定位到问题,比如由于第三方库不存在,无法初始化,导致无法加载扩展名(“A”),当用户配置使用A时,dubbo就会报无法加载扩展名的错误,而不是报哪些扩展名的实现加载失败以及错误原因,这是因为原来的配置格式没有把扩展名的id记录,导致dubbo无法抛出较为精准的异常,这会加大排查问题的难度。所以改成key-value的形式来进行配置。
- 增加了对扩展点 IoC 和 AOP 的支持,一个扩展点可以直接 setter 注入其它扩展点。
Dubbo的SPI使用
创建一个扩展接口并在类上添加@SPI注解代表这是一个Dubbo的SPI接口;并在String simle(URL url,Strings)方法加入@Adaptive注解
package com.alibaba.dubbo.study.day02.adaptive;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.Adaptive;
import com.alibaba.dubbo.common.extension.SPI;
/**
* @author 周宁
* @Date 2019-10-14 20:42
*/
@SPI("ext")
public interface SimpleExt {
@Adaptive("key")
String simple(URL url, String s);
}
创建SimpleExt.java的实现类SimpleExtImpl.java、SecondExtImpl.java
package com.alibaba.dubbo.study.day02.adaptive;
import com.alibaba.dubbo.common.URL;
/**
* @author 周宁
* @Date 2019-10-14 20:48
*/
public class SimpleExtImpl implements SimpleExt{
@Override
public String simple(URL url, String s) {
return "simple"+s;
}
}
package com.alibaba.dubbo.study.day02.adaptive;
import com.alibaba.dubbo.common.URL;
/**
* @author 周宁
* @Date 2019-10-14 20:53
*/
public class SecondExtImpl implements SimpleExt{
@Override
public String simple(URL url, String s) {
return "second"+s;
}
}
在resources文件夹下新建文件/META-INF/dubbo/com.alibaba.dubbo.study.day02.adaptive.SimpleExt文件,内容如下
ext=com.alibaba.dubbo.study.day02.adaptive.SimpleExtImpl
sec=com.alibaba.dubbo.study.day02.adaptive.SecondExtImpl
编写测试类SPITest.java
package com.alibaba.dubbo.study.day02.adaptive;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
/**
* @author 周宁
* @Date 2019-10-14 20:43
*/
public class AdaptvieTest {
public static void main(String[] args) {
SimpleExt simpleExt = ExtensionLoader.getExtensionLoader(SimpleExt.class).getAdaptiveExtension();
System.out.println(simpleExt.simple(URL.valueOf("dubbo://127.0.0.1:9092" + "?key=sec"), " asda"));
SimpleExt simpleExt1 = ExtensionLoader.getExtensionLoader(SimpleExt.class).getDefaultExtension();
System.out.println(simpleExt1.simple(URL.valueOf("asd")," saaaaa"));
}
}
运行测试类看到控制台有如下输出
second asda
simple saaaaa
@SPI
package com.alibaba.dubbo.common.extension;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 扩展接口标记
* <p/>
* 扩展配置文件的更改<br/>
* 以<code> Protocol </ code>为例,其配置文件'META-INF / dubbo / com.xxx.Protocol'从以下内容更改:<br/>
* <pre>
* com.foo.XxxProtocol
* com.foo.YyyProtocol
* </pre>
* <p>
* to key-value pair <br/>
* <pre>
* xxx=com.foo.XxxProtocol
* yyy=com.foo.YyyProtocol
* </pre>
* <br/>
* 发生此更改的原因是:
* <p>
* 如果在扩展实现中有静态字段或方法引用的第三方库,则如果第三方库不存在,则其类将无法初始化。
* 在这种情况下,如果使用以前的格式,dubbo将无法找出扩展名,因此无法将扩展名映射到异常信息。
* <p/>
* 例如
* <p>
* 无法加载Extension(“ mina”)。 当用户配置为使用Mina时,dubbo将告知无法加载扩展,而不是报告哪个提取扩展实现失败和提取原因。
* </p>
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SPI {
/**
* default extension name
* 默认扩展实现的名称
*/
String value() default "";
}
比如在接口上加入@SPI注解后代表这是dubbo的一个可扩展接口,我用协议扩展接口Protocol来举例子,如果使用者在<dubbo:protocol />、<dubbo:service />、<dubbo:reference />都没有指定protocol属性的话,那么就会默认DubboProtocol就是接口Protocol,因为在Protocol上有@SPI("dubbo")注解。而这个protocol属性值或者默认值会被当作该接口的实现类中的一个key,dubbo会去META-INFdubbointernalcom.alibaba.dubbo.rpc.Protocol文件中找该key对应的value
@Adaptive
package com.alibaba.dubbo.common.extension;
import com.alibaba.dubbo.common.URL;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Provide helpful information for {@link ExtensionLoader} to inject dependency extension instance.
*
* 为{@link ExtensionLoader}提供有用的信息以注入依赖项扩展实例。
* @see ExtensionLoader
* @see URL
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Adaptive {
/**
* 确定要注入的目标扩展目标扩展名由URL中传递的参数决定,参数名称由此方法指定。
* <p>
* 如果未从{@link URL}中找到指定的参数,则将使用默认扩展名进行依赖项注入(在其接口的{@link SPI}中指定)。
* <p>
* 例如,给定<code> String [] {“ key1”,“ key2”} </ code>:
* <ol>
* <li>在网址中找到参数“ key1”,将其值用作扩展名</li>
* <li>如果在URL中找不到“ key1”(或其值为空),请尝试使用“ key2”作为扩展名</li>
* <li>如果“ key2”也未出现,请使用默认扩展名</li>
* <li>否则,抛出{@link IllegalStateException}</li>
* </ol>
* 如果没有在接口的{@link SPI}上提供默认扩展名,则使用以下规则从接口的类名生成一个名称:将大写字符的类名分成几部分,
* 并用点号“。”分开,例如: 对于{@code com.alibaba.dubbo.xxx.YyyInvokerWrapper},其默认名称为
* <code> String [] {“ yyy.invoker.wrapper”} </ code>。 此名称将用于从URL搜索参数。
* @return parameter key names in URL
*/
String[] value() default {};
}
- 加在类上:带有@Adaptive注解的类会直接作扩展接口默认实现,在扩展点的多个实现类里只能有一个实现可以加上@Adaptive注解,否则会抛出More than 1 adaptive class found。比如扩展接口ExtensionFactory的多个实现AdaptiveExtensionFactory、SpiExtensionFactory、SpringExtensionFactory;在调用ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()方法获取到的对象始终是AdaptiveExtensionFactory
- 加在方法上:dubbo会给我们生成新的适配器类,比如我们上面的SimpleExt.java类
-
package com.alibaba.dubbo.study.day02.adaptive; import com.alibaba.dubbo.common.URL; import com.alibaba.dubbo.common.extension.Adaptive; import com.alibaba.dubbo.common.extension.SPI; /** * @author 周宁 * @Date 2019-10-14 20:42 */ @SPI("ext") public interface SimpleExt { @Adaptive("key") String simple(URL url, String s); }
- 调用ExtensionLoader.getAdaptiveExtension()最终会给我们生成一个新的Class类内容如下
-
package com.alibaba.dubbo.study.day02.adaptive; import com.alibaba.dubbo.common.extension.ExtensionLoader; public class SimpleExt$Adaptive implements com.alibaba.dubbo.study.day02.adaptive.SimpleExt { public java.lang.String simple(com.alibaba.dubbo.common.URL arg0, java.lang.String arg1) { if (arg0 == null) throw new IllegalArgumentException("url == null"); com.alibaba.dubbo.common.URL url = arg0; String extName = url.getParameter("key", "ext"); if (extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.study.day02.adaptive.SimpleExt) name from url(" + url.toString() + ") use keys([key])"); com.alibaba.dubbo.study.day02.adaptive.SimpleExt extension = (com.alibaba.dubbo.study.day02.adaptive.SimpleExt) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.study.day02.adaptive.SimpleExt.class).getExtension(extName); return extension.simple(arg0, arg1); } }
- 所以我们便可以解释上述AdaptvieTest测试的输出结果:首先从URL类型参数中找到有没有"key"键对应的值,没有则使用@SPI注解提供的默认值"ext"。在我们的demo里URL为"dubbo://127.0.0.1:9092" + "?key=sec"程序返回的extName是"sec"也就是说最终选择的扩展实现类为sec=com.alibaba.dubbo.study.day02.adaptive.SecondExtImpl。
- 这样就比较清楚这个适配器如何去选择哪个实现类作为本次需要调用的类,这里最关键的还是强调了dubbo以URL为总线,运行过程中所有的状态数据信息都可以通过URL来获取,比如当前系统采用什么序列化,采用什么通信,采用什么负载均衡等信息,都是通过URL的参数来呈现的,所以在框架运行过程中,运行到某个阶段需要相应的数据,都可以通过对应的Key从URL的参数列表中获取。
@Activate:按照@Activate注解配置的group和value属性激活相应的多个扩展点
package com.alibaba.dubbo.common.extension;
import com.alibaba.dubbo.common.URL;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 此注释对于根据给定条件自动激活某些扩展名很有用,例如:<code> @Activate </ code>可用于在有多个实现时加载某些
* <code> Filter </ code>扩展名。
* <ol>
* <li>{@link Activate#group()}指定组条件。 框架SPI定义有效的组值。
* <li>{@link Activate#value()}在{@link URL}条件中指定参数密钥。
* </ol>
* SPI提供者可以调用{@link ExtensionLoader#getActivateExtension(URL,String,String)}来找出具有给定条件的所有激活的扩展。
* @see SPI
* @see URL
* @see ExtensionLoader
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Activate {
/**
* 当其中的一个group匹配时激活当前的扩展实现。通过{@link ExtensionLoader#getActivateExtension(URL, String, String)}
* 传递的group参数将会被用来匹配
*
* @return group names to match
* @see ExtensionLoader#getActivateExtension(URL, String, String)
*/
String[] group() default {};
/**
* 当指定的键出现在URL的参数中时,激活当前扩展名。
* <p>
* 例如,给定<code> @Activate(“ cache,validation”)</ code>,
* 仅当出现<code> cache </ code>或<code> validation </ code>键时,才返回当前扩展名 在网址的参数中。
* </p>
*
* @return URL parameter keys
* @see ExtensionLoader#getActivateExtension(URL, String)
* @see ExtensionLoader#getActivateExtension(URL, String, String)
*/
String[] value() default {};
/**
* Relative ordering info, optional
*
* @return extension list which should be put before the current one
*/
String[] before() default {};
/**
* Relative ordering info, optional
*
* @return extension list which should be put after the current one
*/
String[] after() default {};
/**
* Absolute ordering info, optional
*
* @return absolute ordering info
*/
int order() default 0;
}
对于集合类扩展点,比如:Filter
, InvokerListener
, ExportListener
, TelnetHandler
, StatusChecker
等,可以同时加载多个实现,此时,可以用自动激活来简化配置,如:
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.Filter;
@Activate // 无条件自动激活
public class XxxFilter implements Filter {
// ...
}
或
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.Filter;
@Activate("xxx") // 当配置了xxx参数,并且参数为有效值时激活,比如配了cache="lru",自动激活CacheFilter。
public class XxxFilter implements Filter {
// ...
}
或
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.Filter;
@Activate(group = "provider", value = "xxx") // 只对提供方激活,group可选"provider"或"consumer"
public class XxxFilter implements Filter {
// ...
}
ExtensionLoader:该类是Dubbo SPI实现的核心类。
ExtensionLoader的成员变量
- 基础配置类:配置文件目录地址、正则表达式
/**
* 这是jdk的SPI扩展机制中配置文件路径,dubbo为了兼容jdk的SPI
*/
private static final String SERVICES_DIRECTORY = "META-INF/services/";
/**
* 用于用户自定义的扩展实现配置文件存放路径
*/
private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
/**
* 用于dubbo内部提供的扩展实现配置文件存放路径
*/
private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
- 全局缓存,扩展接口——加载扩展类对象(ExtensionLoader);扩展实现类—扩展实现对象
/**
* 扩展加载器集合,key为扩展接口,例如Protocol等
*/
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
/**
* 扩展实现集合,key为扩展实现类,value为扩展对象
* 例如key为Class<DubboProtocol>,value为DubboProtocol对象
*/
private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();
- 针对ExtensionLoader对象的属性,提升性能的其他缓存
/**
* 扩展接口,例如Protocol.class等
*/
private final Class<?> type;
/**
* 对象工厂,获得扩展实现的实例,用于injectExtension方法中将扩展实现类的实例注入到相关的依赖属性。
* 比如StubProxyFactoryWrapper类中有Protocol protocol属性,就是通过set方法把Protocol的实现类实例赋值
*/
private final ExtensionFactory objectFactory;
/**
* 以下提到的扩展名就是在配置文件中的key值,类似于“dubbo”等
* key-扩展实现类(比如DubboProtocol.class) value-dubbo
*/
private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>();
/**
* 缓存的扩展实现类集合key为扩展实现类名称(比如"dubbo") value对应的实现类(DubboProtocol)
*/
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();
/**
* 扩展名与加有@Activate的自动激活类的映射
*/
private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>();
/**
* 缓存的扩展对象集合,key为扩展名,value为扩展对象
* 例如Protocol扩展,key为dubbo,value为DubboProcotol
*/
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
/**
* 缓存的自适应( Adaptive )扩展对象,例如例如AdaptiveExtensionFactory类的对象
*/
private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
/**
* 缓存的自适应扩展对象的类,例如AdaptiveExtensionFactory类
*/
private volatile Class<?> cachedAdaptiveClass = null;
/**
* 缓存的默认扩展名,就是@SPI中设置的值
*/
private String cachedDefaultName;
/**
* 创建cachedAdaptiveInstance异常
*/
private volatile Throwable createAdaptiveInstanceError;
/**
* 拓展Wrapper实现类集,如ProtocolFilterWrapper
*/
private Set<Class<?>> cachedWrapperClasses;
/**
* 拓展名与加载对应拓展类发生的异常的映射
*/
private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<String, IllegalStateException>();
ExtensionLoader的构造函数
private ExtensionLoader(Class<?> type) {
this.type = type;
//如果type是ExtensionFactory的话好说了,直接为null,否则使用Dubbo自己提供的SPI机制获取
//这里返回的永远是AdaptiveExtensionFactory
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
ExtensionLoader的方法
1.getExtensionLoader(Class<T> type):获取扩展接口比如Protocol.class的ExtensionLoader,如果是我们上文的Demo就是获取SimpleExt 扩展接口的ExtensionLoader
@SuppressWarnings("unchecked")
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
//扩展点接口为空,抛出异常
if (type == null)
throw new IllegalArgumentException("Extension type == null");
//type不是接口
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!");
}
//找到type对应的扩展加载器
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
//如果为空,则创建一个ExtensionLoader,并添加到EXTENSION_LOADERS缓存起来
if (loader == null) {
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
2.getExtension(String name):该方法用于查找具有给定名称扩展实现,比如查找"dubbo"的扩展实现DubboProtocol的对象
- a.根据传递进来的name是否为true判断是否应该获取默认的扩展实现;然后就是从缓存中获取扩展实现对象;如果未找到,调用createExtension(name)创建,并加入缓存。
public T getExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name == null");
//传入的name是"true"返回默认的扩展类
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) {
//对holder加锁
synchronized (holder) {
instance = holder.get();
if (instance == null) {
//通过扩展名创建扩展接口对应的实现类
instance = createExtension(name);
//放入holder缓存起来
holder.set(instance);
}
}
}
return (T) instance;
}
- b.getDefaultExtension()查找默认的扩展类实现对象
public T getDefaultExtension() {
getExtensionClasses();
if (null == cachedDefaultName || cachedDefaultName.length() == 0
|| "true".equals(cachedDefaultName)) {
return null;
}
return getExtension(cachedDefaultName);
}
- c.createExtension(String name)该方法通过扩展名获取扩展对象实例;
private T createExtension(String name) {
//根据名称获取扩展类的实现
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
//抛出异常
throw findException(name);
}
try {
//根据扩展实现类的类型后去扩展实现类的实例
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
//不存在是吧,那就反射创建
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
//向对象中注入依赖的属性(自动装配)
injectExtension(instance);
//创建 Wrapper 扩展对象(自动包装)
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);
}
}
首先是通过getExtensionClasses()从配置文件(/META-INF/dubbo/xxx或者/META-INF/dubbo/internal/xxx或者)加载所有type的接口实现类,然后从EXTENSION_INSTANCES缓存获取扩展类的实例对象,不存在的话通过反射创建;然后给创建的扩展实现类对象注入属性;最后判断该扩展接口有没有包装类,有的话创建扩展实现类对象的包装对象,以同样的方式注入属性。
- d.getExtensionClasses(),首先从缓存cachedClasses中去取,取到直接 返回,如果为null则调用loadExtensionClasses()方法从配置文件读取
private Map<String, Class<?>> getExtensionClasses() {
//获取缓存的扩展类的Class
Map<String, Class<?>> classes = cachedClasses.get();
if (classes == null) {
synchronized (cachedClasses) {
//获取classes
classes = cachedClasses.get();
if (classes == null) {
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
}
- e.loadExtensionClasses(),该方法前半部分,主要是解析扩展接口的@SPI注解属性,并将解析出来的扩展接口的默认实现类的名称放入到缓存cachedDefaultName,后半部分调用loadDirectory(Map<String, Class<?>> extensionClasses, String dir)方法分别解析三个目录下配置的扩展接口的实现类文件
private Map<String, Class<?>> loadExtensionClasses() {
//SPI注解,在创建ExtensionLoader对象时候已经初始化了type
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
//如果SPI注解存在
if (defaultAnnotation != null) {
//SPI注解的value属性
String value = defaultAnnotation.value();
if ((value = value.trim()).length() > 0) {
//只允许有一个默认值
String[] names = NAME_SEPARATOR.split(value);
if (names.length > 1) {
throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
+ ": " + Arrays.toString(names));
}
if (names.length == 1) cachedDefaultName = names[0];
}
}
//从目录META-INF/services/,META-INF/dubbo,META-INF/dubbo/internal 下配置文件
//加载实现类数组
Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
loadDirectory(extensionClasses, DUBBO_DIRECTORY);
loadDirectory(extensionClasses, SERVICES_DIRECTORY);
return extensionClasses;
}
- f.loadDirectory(Map<String, Class<?>> extensionClasses, String dir);拼接扩展接口的实现类配置文件,使用classLoader加载配置
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) {
//拼接接口限定名称获得完整文件名
String fileName = dir + type.getName();
try {
Enumeration<java.net.URL> urls;
//查找当前类的classLoader
ClassLoader classLoader = findClassLoader();
//使用类加载器找到文件fileName
if (classLoader != null) {
urls = classLoader.getResources(fileName);
} else {
urls = ClassLoader.getSystemResources(fileName);
}
if (urls != null) {
//遍历文件
while (urls.hasMoreElements()) {
java.net.URL resourceURL = urls.nextElement();
loadResource(extensionClasses, classLoader, resourceURL);
}
}
} catch (Throwable t) {
logger.error("Exception when load extension class(interface: " +
type + ", description file: " + fileName + ").", t);
}
}
- g.loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL);解析文件中每一行内容,其中该方法会跳过#注释掉的内容,然后读到的每行数据用"="拆分,第一个就是扩展实现类名称,第二个是对应的实现类
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;
while ((line = reader.readLine()) != null) {
//这一行有#字符串
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) {
name = line.substring(0, i).trim();
line = line.substring(i + 1).trim();
}
if (line.length() > 0) {
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);
}
}
- h.loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name);
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
//clazz是否实现了接口啊
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.");
}
//该实现类有Adaptive注解 赋值cachedAdaptiveClass
//后续实例化类不会动态生成代码了,直接实例化clazz对象并缓存到cachedAdaptiveInstance
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());
}
//比如ProtocolFilterWrapper就是一个包装类
} else if (isWrapperClass(clazz)) {
Set<Class<?>> wrappers = cachedWrapperClasses;
if (wrappers == null) {
cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
wrappers = cachedWrapperClasses;
}
//添加包装类
wrappers.add(clazz);
} else {
//构造函数合法性判断,
clazz.getConstructor();
//未配置name生成一个 兼容javaSPI的配置
if (name == null || name.length() == 0) {
//从@Extension注解查找,没有的话 生成一个
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);
//如果是自动激活的实现类,则加入到缓存
if (activate != null) {
cachedActivates.put(names[0], activate);
}
for (String n : names) {
//如果cachedNames没有缓存该扩展实现类对应的扩展名称
//则放入缓存中
if (!cachedNames.containsKey(clazz)) {
cachedNames.put(clazz, n);
}
//加入到extensionClasses中!
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());
}
}
}
}
}
private boolean isWrapperClass(Class<?> clazz) {
try {
//比如ProtocolFilterWrapper就返回true
clazz.getConstructor(type);
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
private String findAnnotationName(Class<?> clazz) {
com.alibaba.dubbo.common.Extension extension = clazz.getAnnotation(com.alibaba.dubbo.common.Extension.class);
if (extension == null) {
String name = clazz.getSimpleName();
if (name.endsWith(type.getSimpleName())) {
name = name.substring(0, name.length() - type.getSimpleName().length());
}
return name.toLowerCase();
}
return extension.value();
}
该方法先判断扩展实现类类型是否为我们扩展接口的实现类;判断该扩展接口实现类有没有使用@Adaptive注解,如果有缓存该类到cachedAdaptiveClass;判断该接口是否为包装类,是的话缓存该类到cachedWrapperClasses;然后就是判断扩展接口的实现类的构造函数合法性(必须有无参构造),兼容Java SPI的配置给扩展实现类生成一个名称,解析该实现类的@Activate注解缓存到cachedActivates中,缓存该实现类与实现类名称的到cachedNames,最后将name与实现类的映射放入extensionClasses。
- i.injectExtension(T instance)使用objectFactory给实例对象的set方法进行属性注入,objectFactory在创建ExtensionLoader时就已经初始化了。
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
//反射获取该类中的所有方法
for (Method method : instance.getClass().getMethods()) {
//如果是set方法
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 {
//如果是setProtocol方法则property为protocol
String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
//使用objectFactory属性获取对象
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;
}
3.getAdaptiveExtension():实现获取扩展接口的自适应扩展对象
- a.从缓存cachedAdaptiveInstance对象获取,存在直接返回,不存在需要调用createAdaptiveExtension()方法创建,然后放入缓存中
public T getAdaptiveExtension() {
//首先从缓存的自适应扩展对象中获取
Object instance = cachedAdaptiveInstance.get();
//还未创建
if (instance == null) {
//创建并未出现异常
if (createAdaptiveInstanceError == null) {
//加锁
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
//创建自适应拓展对象
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;
}
- b.createAdaptiveExtension():获取自适应扩展对象的Class并使用Class反射创建自适应扩展对象,最后自动注入
private T createAdaptiveExtension() {
try {
//创建一个AdaptiveExtensionClass并注入值
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
}
}
- c.getAdaptiveExtensionClass()获取自适应扩展类,如果通过getExtensionClasses()已经加载了直接返回,否则调用createAdaptiveExtensionClass()方法!
private Class<?> getAdaptiveExtensionClass() {
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
- d.createAdaptiveExtensionClass()生成SimpleExt$Adaptive这种对象的方法,首先使用createAdaptiveExtensionClassCode()方法创建自适应对象的字符串代码,然后通过Dubbo SPI扩展机制选取一个Compiler编译字符串代码为Class对象
//创建动态生成的适配器类代码
String code = createAdaptiveExtensionClassCode();
//获取classLoader
ClassLoader classLoader = findClassLoader();
com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
//编译生成的代码并返回Class对象实例
return compiler.compile(code, classLoader);
- e.createAdaptiveExtensionClassCode()该方法生成自适应扩展类的代码,具体方法不分析了,但是生成的代码字符串我放一下,如下
package com.alibaba.dubbo.study.day02.adaptive;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class SimpleExt$Adaptive implements com.alibaba.dubbo.study.day02.adaptive.SimpleExt {
public java.lang.String simple(com.alibaba.dubbo.common.URL arg0, java.lang.String arg1) {
if (arg0 == null) throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg0;
String extName = url.getParameter("key", "ext");
if (extName == null)
throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.study.day02.adaptive.SimpleExt) name from url(" + url.toString() + ") use keys([key])");
com.alibaba.dubbo.study.day02.adaptive.SimpleExt extension = (com.alibaba.dubbo.study.day02.adaptive.SimpleExt) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.study.day02.adaptive.SimpleExt.class).getExtension(extName);
return extension.simple(arg0, arg1);
}
}
4.getActivateExtension(URL url, String[] values, String group):获得自动激活的扩展对象,比如Dubbo中的Filter需要同时激活多个因为每个Filter功能不同。
/**
* 获得激活的扩展对象
*
* @param url
* @param values
* @param group
* @return
*/
public List<T> getActivateExtension(URL url, String[] values, String group) {
//扩展对象
List<T> exts = new ArrayList<T>();
List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values);
//配置项key对应的配置values[]数组不包含"-default"这种属性,这种属性代表删除所有默认的比如()
//<dubbo:service filter="-default" />代表删除所有过滤器
if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
//获得扩展实现类数组,把扩展实现类放到cachedClasses中
getExtensionClasses();
/**
* 这一步主要是添加所有带有@Activate注解的扩展点实现类
*/
for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {
//扩展实现类名称
String name = entry.getKey();
//Activate注解
Activate activate = entry.getValue();
//判断group值是否存在所有自动激活类中group组中,匹配分组
if (isMatchGroup(group, activate.group())) {
//扩展实现类是否需要加入到exts中判断
T ext = getExtension(name);
//如果扩展点名称不包含在自定义的里
//并且没有显示的删除掉这个扩展点
//判断是否激活
if (!names.contains(name)
&& !names.contains(Constants.REMOVE_VALUE_PREFIX + name)
&& isActive(activate, url)) {
exts.add(ext);
}
}
}
//排序
Collections.sort(exts, ActivateComparator.COMPARATOR);
}
/**
* 通过names添加自定义的扩展点实现配置
*/
List<T> usrs = new ArrayList<T>();
//遍历values中指定的
for (int i = 0; i < names.size(); i++) {
String name = names.get(i);
//不以"-"开通
//并且names里面不包含-name的配置
if (!name.startsWith(Constants.REMOVE_VALUE_PREFIX)
&& !names.contains(Constants.REMOVE_VALUE_PREFIX + name)) {
//在配置中把自定义的配置放在自动激活的扩展对象前面,可以让自定义的配置先加载
//例如,<dubbo:service filter="demo,default,demo2" /> ,则 DemoFilter 就会放在默认的过滤器前面。
//如果name是default
if (Constants.DEFAULT_KEY.equals(name)) {
//usrs不为空
if (!usrs.isEmpty()) {
exts.addAll(0, usrs);
usrs.clear();
}
} else {
//获得名称为name的扩展对象
T ext = getExtension(name);
usrs.add(ext);
}
}
}
//添加到etxs集合中
if (!usrs.isEmpty()) {
exts.addAll(usrs);
}
return exts;
}
- a.首先是判断values[]中有没有"-default"字符串,有的话表示禁用所有自动激活的扩展实现对象(带有@Activate的扩展实现类的对象);逻辑首先匹配自动激活的扩展实现对象分组可匹配,然后判断自动激活的扩展实现对象并没有包含在values[]里,并且没有通过-"name"这种方式移除掉自动激活的扩展对象然后就是
/**
* group条件是匹配不
* @param group
* @param groups
* @return
*/
private boolean isMatchGroup(String group, String[] groups) {
//如果@Active注解没有设置group属性,那么直接匹配成功
if (group == null || group.length() == 0) {
return true;
}
if (groups != null && groups.length > 0) {
for (String g : groups) {
if (group.equals(g)) {
return true;
}
}
}
return false;
}
private boolean isActive(Activate activate, URL url) {
//该自动激活的扩展实现类型适用于那些value
String[] keys = activate.value();
if (keys.length == 0) {
return true;
}
for (String key : keys) {
//只有url中有参数匹配上了我指定的value才能够用
for (Map.Entry<String, String> entry : url.getParameters().entrySet()) {
String k = entry.getKey();
String v = entry.getValue();
if ((k.equals(key) || k.endsWith("." + key))
&& ConfigUtils.isNotEmpty(v)) {
return true;
}
}
}
return false;
}
- b.添加通过values[]指定的不是自动激活的自定义扩展点实现配置,并且需要注意的是有些需要排在default前面的处理
- c.返回所有激活的自定义扩展对象集合
ExtensionFactory:
在ExtensionLoader中有个属性如下
/**
* 对象工厂,获得扩展实现的实例,用于injectExtension方法中将扩展实现类的实例注入到相关的依赖属性。
* 比如StubProxyFactoryWrapper类中有Protocol protocol属性,就是通过set方法把Protocol的实现类实例赋值
*/
private final ExtensionFactory objectFactory;
并且它在ExtensionLoader构造函数中完成了初始化,他的主要目的就是帮助我们实现扩展接口实现类的自动注入。
他有三个实现类
SpiExtensionFactory.java:获取dubbo自适应扩展对象
/**
* SpiExtensionFactory
*/
public class SpiExtensionFactory implements ExtensionFactory {
@Override
public <T> T getExtension(Class<T> type, String name) {
//根据名称获取类型为type的name扩展名的扩展实现类
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
//获取ExtensionLoader
ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
if (!loader.getSupportedExtensions().isEmpty()) {
return loader.getAdaptiveExtension();
}
}
return null;
}
}
SpringExtensionFactory.java:从Spring的上下文中获取一个bean
public <T> T getExtension(Class<T> type, String name) {
for (ApplicationContext context : contexts) {
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());
if (Object.class == type) {
return null;
}
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;
}
AdaptiveExtensionFactory.java:该类带有@Adaptive注解即默认情况下使用getAdaptiveExtension()方法获取ExtensionFactory.class的扩展对象总会是AdaptiveExtensionFactory(ExtensionLoader的objectFactory成员变量便是如此)。他是从两个ExtensionFactory的实现SpringExtensionFactory和SpiExtensionFactory有序获取扩展实现对象。顺序为SPI->Spring
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
private final List<ExtensionFactory> factories;
public AdaptiveExtensionFactory() {
//把所有实现了ExtensionFactory扩展类对象加入到集合中SpiExtensionFactory 和 SpringExtensionFactory,SpiExtensionFactory会一直排在SpringExtensionFactory前面
ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
for (String name : loader.getSupportedExtensions()) {
list.add(loader.getExtension(name));
}
factories = Collections.unmodifiableList(list);
}
@Override
public <T> T getExtension(Class<T> type, String name) {
//遍历
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
}
}