1. SPI(Service Provider Interface)
1.1 JDK SPI机制
设计目标:面向对象的设计里模块之间是基于接口编程,模块之间不对实现类进行硬编码,一旦代码里涉及具体的实现类就违反了可插拔的原则如果需要替换一种实现就需要修改代码。不在模块中写死代码,这就是一种服务发现机制。这就是SPI机制,将装配的控制权移到代码之外。
Java SPI(Service Provider Interface)的具体约定如下:当服务的提供者提供了服务接口的一种实现之后,在jar包的META-INF/services/目录中同时创建一个以服务接口命名的文件,该文件中的内容就是实现该服务接口的具体类。ServiceLoader来加载spi类
META-INF/services
Dubbo SPI:如果使用jdk spi就会一次性实例化所有的实现,耗费资源;增加了对扩展点
dubbo = com.fang.spi.Test通过这个key来加载,就不用全部加载了
1.2 JDK SPI不足之处
a. JDK标准的SPI会一次性实例化扩展点所有实现,如果有的没有用上也会加载很浪费资源。
b. 扩展点没有对IOC和AOP的支持
c. 一个扩展点不能直接setter注入其他的扩展点。
1.3 Dubbo SPI
dubbo spi的目的:获取一个实现类的对象。
途径:ExtensionLoader.getExtension(String name)
实现路径:
getExtensionLoader(Class<T> type) 就是为該接口new 一个ExtensionLoader然后缓存起来。
getAdaptiveExtension() 获取一个扩展类的对象,这个类有一个规则如果它没有一个@Adaptive注解就动态创建一个装饰类例如Protocol$Adaptive对象。????这里的装饰类可以认为是一个AOP,refprotocol.refer()实现方法时路由到Protocol$Adaptive, 然后由其路由到具体的实现类中进行装饰,最终回到原本的Protocol实现比如RegistryProtocol。
getExtensionName(String name) 获取一个对象。这里是Dubbo实现IOC控制反转的关键。在编译类Protocol$Adaptive中执行getExtensionName("dubbo")的时候会
关于ObjectFactoy的细节:
1. objectFactory就是ExtensionFactory
2. objectFactory作用,他就是为Dubbo提供IOC对象
1.4 Adaptive
注解在类上:代表人工实现编码即实现了一个装饰类例如ExtensionFactory
注解在方法上:代表自动生成和编译一个动态的adapive类如Protocol$Adaptive
2. Dubbo的IOC和AOP
Dubbo的IOC控制反转,在如
Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension()
// 这些Adaptive编译生成Protocol&Adaptive动态代码之后并进入
Cluster extension = (Cluster) ExtensionLoader.getExtensionLoader(Cluster.class).getExtension(extName);
// 在getExtension中为extName的RegistryProtocol方法的每个set注入相应的$动态编译方法,实现控制反转
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {
Class<?> pt = method.getParameterTypes()[0];
try {
String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
method.invoke(instance, object);
}
} catch (Exception e) {
logger.error("fail to inject via method " + method.getName()
+ " of interface " + type.getName() + ": " + e.getMessage(), e);
}
}
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return instance;
AOP的动态代理则是根据cachedWrapperClasses,这个set的定义是只有当该class无Adpative注解且构造函数包含目标接口才能。目前只有Adaptive的 ,然后对目标对象实现构造重新包装成新的Protocol对象,同时在进行IOC反转完成整个的过程。
if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
for (Class<?> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}