在架构师集合之类加载器(ClassLoader)篇中,简单介绍了java的SPI,那么SPI有什么缺点呢?
SPI的缺点
-
不能按需加载。虽然 ServiceLoader 做了延迟载入,但是基本只能通过遍历全部获取,也就是接口的实现类得全部载入并实例化一遍。如果你并不想用某些实现类,或者某些类实例化很耗时,它也被载入并实例化了,这就造成了浪费。
-
获取某个实现类的方式不够灵活,只能通过 Iterator 形式获取,不能根据某个参数来获取对应的实现类。
-
多个并发多线程使用 ServiceLoader 类的实例是不安全的。
-
加载不到实现类时抛出并不是真正原因的异常,错误很难定位。
dubbo的SPI机制
dubbo因为有很多接口和实现类,所以也广泛了应用了SPI, Dubbo的SPI并非原生的SPI,Dubbo的规则是在
-
/META-INF/dubbo
-
/META-INF/dubbo/internal
-
/META-INF/service
目录下,并且基于SPI接口去创建一个文件下面以需要实现的接口去创建一个文件,并且在文件中以properties规则一样配置实现类的全面以及分配实现的一个名称。文件名称和接口名称保持一致,文件内容和SPI有差异,内容是key对应value。
我们先来看一个demo。
package com.example.studydemo.spi;
@SPI("dataBase")
public interface Search {
void search();
}
public class FileSearchImpl implements Search {
@Override
public void search() {
System.out.println("文件搜索");
}
}
public class DataBaseSearchImpl implements Search {
@Override
public void search() {
System.out.println("数据库搜索");
}
}
在META-INF/dubbo 路径下创建Search文件:
dataBase=com.example.studydemo.spi.DataBaseSearchImpl
file=com.example.studydemo.spi.FileSearchImpl
编写测试类进行测试,内容如下:
public class DubboSpiTest {
public static void main(String[] args) {
ExtensionLoader<Search> extensionLoader = ExtensionLoader.getExtensionLoader(Search.class);
Search fileSearch = extensionLoader.getExtension("file");
fileSearch.search();
Search dataBaseSearch = extensionLoader.getExtension("dataBase");
dataBaseSearch.search();
System.out.println(extensionLoader.getDefaultExtensionName());
Search defaultSearch = extensionLoader.getDefaultExtension();
defaultSearch.search();
}
}
结果为:
通过这个简单的demo,我们就知道dubbo的SPI是怎么使用了。
dubbo的Adaptive机制
Dubbo提供了一种SPI的机制用于动态的加载扩展类,但是如何在运行时动态的选用哪一种扩展类来提供服务,这就需要一种机制来进行动态的匹配。Dubbo SPI中提供的Adaptive机制就为解决这个问题提供了一种良好的解决方案。
我们接下来看一下demo:
@SPI("apple")
public interface FruitGranter {
Fruit grant();
@Adaptive
String watering(URL url);
}
// 苹果种植者
public class AppleGranter implements FruitGranter {
@Override
public Fruit grant() {
return new Apple();
}
@Override
public String watering(URL url) {
System.out.println("watering apple");
return "watering finished";
}
}
// 香蕉种植者
public class BananaGranter implements FruitGranter {
@Override
public Fruit grant() {
return new Banana();
}
@Override
public String watering(URL url) {
System.out.println("watering banana");
return "watering success";
}
}
public class ExtensionLoaderTest {
@Test
public void testGetExtensionLoader() {
// 首先创建一个模拟用的URL对象
URL url = URL.valueOf("dubbo://192.168.0.101:20880?fruit.granter=apple");
// 通过ExtensionLoader获取一个FruitGranter对象
FruitGranter granter = ExtensionLoader.getExtensionLoader(FruitGranter.class)
.getAdaptiveExtension();
// 使用该FruitGranter调用其"自适应标注的"方法,获取调用结果
String result = granter.watering(url);
System.out.println(result);
}
}
在META-INF/dubbo下创建一个文件,该文件的名称是目标接口的全限定名,这里是org.apache.dubbo.demo.example.eg19.FruitGranter,在该文件中需要指定该接口所有可提供服务的子类,形式如:
apple=org.apache.dubbo.demo.example.eg19.AppleGranter
banana=org.apache.dubbo.demo.example.eg19.BananaGranter
结果打印为:
watering apple
watering finished
通过这个简单的demo就知道@Adaptive的作用是什么了。
dubbo的SPI源码解析
首先我们看看getExtensionLoader方法:
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
if (type == null)
throw new IllegalArgumentException("Extension type == null");
if (!type.isInterface()) {
throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
}
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type(" + type +
") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
}
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
//这里有个构造函数
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
这是一个静态的工厂方法,要求传入的类型必须为接口并且有SPI的注解,用map做了个缓存,key为接口的class对象,而value是 ExtensionLoader对象。我们看看new ExtensionLoader(type)做了什么:
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
其实就是给type赋值,全局可以使用了,然后给objectFactory 赋值,这里走的是ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()),获取默认的ExtensionFactory实现,就是AdaptiveExtensionFactory,为什么,下面会讲,因为循环了,这里只能带过,后面讲了之后可以回过头来再看。
接下来看看 getExtension方法:
public T getExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name == null");
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();
//这里有个高并发的双重检查,确保instance唯一
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
//重点看这个方法
instance = createExtension(name);
holder.set(instance);
}
}
}
return (T) instance;
}
...
private T createExtension(String name) {
//重点看这个方法,根据传入的扩展名获取对应的class。
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
//根据class去缓存中获取实例,如果没有的话,通过反射创建对象并放入缓存。
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
//依赖注入,完成对象实例的初始化。
injectExtension(instance);
//创建wrapper对象。也就是说,此处返回的对象不一定是具体的实现类,可能是包装的对象。
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && wrapperClasses.size() > 0) {
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);
}
}
这段代码由几部分组成:
-
根据传入的扩展名获取对应的class。
-
根据class去缓存中获取实例,如果没有的话,通过反射创建对象并放入缓存。
-
依赖注入,完成对象实例的初始化。
-
创建wrapper对象。也就是说,此处返回的对象不一定是具体的实现类,可能是包装的对象。
getExtensionClasses方法:
private Map<String, Class<?>> getExtensionClasses() {
Map<String, Class<?>> classes = cachedClasses.get();
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
//加载文件,重点看这里
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
}
...
private Map<String, Class<?>> loadExtensionClasses() {
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation != null) {
String value = defaultAnnotation.value();
if (value != null && (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];
}
}
Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
//加载META-INF/dubbo/internal/目录下的文件
loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
//加载META-INF/dubbo/目录下的文件
loadFile(extensionClasses, DUBBO_DIRECTORY);
//加载META-INF/services/目录下的文件
loadFile(extensionClasses, SERVICES_DIRECTORY);
return extensionClasses;
}
...
private void loadFile(Map<String, Class<?>> extensionClasses, String dir) {
String fileName = dir + type.getName();
try {
Enumeration<java.net.URL> urls;
ClassLoader classLoader = findClassLoader();
if (classLoader != null) {
urls = classLoader.getResources(fileName);
} else {
urls = ClassLoader.getSystemResources(fileName);
}
if (urls != null) {
while (urls.hasMoreElements()) {
java.net.URL url = urls.nextElement();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));
try {
String line = null;
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) {
Class<?> clazz = Class.forName(line, true, classLoader);
//判断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这个注解是否在实现类上
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());
}
} else {
try {
clazz.getConstructor(type);
Set<Class<?>> wrappers = cachedWrapperClasses;
if (wrappers == null) {
cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
wrappers = cachedWrapperClasses;
}
wrappers.add(clazz);
} catch (NoSuchMethodException e) {
clazz.getConstructor();
if (name == null || name.length() == 0) {
name = findAnnotationName(clazz);
if (name == null || name.length() == 0) {
if (clazz.getSimpleName().length() > type.getSimpleName().length()
&& clazz.getSimpleName().endsWith(type.getSimpleName())) {
name = clazz.getSimpleName().substring(0, clazz.getSimpleName().length() - type.getSimpleName().length()).toLowerCase();
} else {
throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + url);
}
}
}
String[] names = NAME_SEPARATOR.split(name);
if (names != null && names.length > 0) {
//获取Activate注解
Activate activate = clazz.getAnnotation(Activate.class);
if (activate != null) {
cachedActivates.put(names[0], activate);
}
for (String n : names) {
if (!cachedNames.containsKey(clazz)) {
cachedNames.put(clazz, n);
}
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());
}
}
}
}
}
}
} catch (Throwable t) {
IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + url + ", cause: " + t.getMessage(), t);
exceptions.put(line, e);
}
}
} // end of while read lines
} finally {
reader.close();
}
} catch (Throwable t) {
logger.error("Exception when load extension class(interface: " +
type + ", class file: " + url + ") in " + url, t);
}
} // end of while urls
}
} catch (Throwable t) {
logger.error("Exception when load extension class(interface: " +
type + ", description file: " + fileName + ").", t);
}
}
调用loadFile方法,代码比较长,主要做了几个事情
-
cachedAdaptiveClass : 当Adaptive注解在实现类上时,赋值给它。 当前Extension类型对应的AdaptiveExtension类型(只能一个)
-
cachedWrapperClasses : 当有有参构造时,添加到它里面。 当前Extension类型对应的所有Wrapper实现类型(无顺序)
-
cachedActivates : 当没有有参构造就使用无参构造,获取有Activates注解的类,放入cache缓存中。当前Extension实现自动激活实现缓存(map,无序)
-
cachedNames : 没有有参构造就使用无参构造,存入这个map中。扩展点实现类对应的名称(如配置多个名称则值为第一个)
当loadExtensionClasses方法执行完成之后,还有以下变量被赋值:
-
cachedDefaultName : 当前扩展点的默认实现名称
-
当getExtensionClasses方法执行完成之后,除了上述变量被赋值之外,还有以下变量被赋值:
cachedClasses : 扩展点实现名称对应的实现类(一个实现类可能有多个名称)
其实也就是说,在调用了getExtensionClasses方法之后,当前扩展点对应的实现类的一些信息就已经加载进来了并且被缓存了。后面的许多操作都可以直接通过这些缓存数据来进行处理了。
dubbo的IOC(injectExtension方法,ioc的实现方法):
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;
}
这个方法实现了依赖注入,即IOC。首先通过反射获取到实例的方法;然后遍历,获取setter方法;接着从objectFactory中获取依赖对象;最后通过反射调用setter方法注入依赖。
这里要注意Object object = objectFactory.getExtension(pt, property);这个方法,其中的objectFactory实例为 AdaptiveExtensionFactory实例。那么如果本身类就是ExtensionFactory类,从前面构造函数中objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());可以得知,那么objectFactory就是null了。
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
private final List<ExtensionFactory> factories;
public AdaptiveExtensionFactory() {
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);
}
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;
}
}
为啥是它呢?不应该是@SPI指定或者url指定方法么,这里@Adaptive放在类上,那么自然优先指定是它。而ExtensionLoader loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);这里就会获取/META-INF/dubbo/internal配置文件com.alibaba.dubbo.common.extension.ExtensionFactory,然后把里面的实例都装入List factories中。我们可以看到有两个实现类。
spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory
adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
public class SpiExtensionFactory implements ExtensionFactory {
public <T> T getExtension(Class<T> type, String name) {
//type是接口类型,且必须含有@SPI注解
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
//获取type的所有ExtensionClasses实现的key(例如:type是Protocol.class)
if (loader.getSupportedExtensions().size() > 0) {
//获取type的装饰类,如果有@Adaptive注解的类,则返回该类的实例,否则返回一个动态代理的实例(如:Protocol$Adaptive 的实例)
return loader.getAdaptiveExtension();
}
}
return null;
}
}
public class SpringExtensionFactory implements ExtensionFactory {
private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>();
public static void addApplicationContext(ApplicationContext context) {
contexts.add(context);
}
public static void removeApplicationContext(ApplicationContext context) {
contexts.remove(context);
}
@SuppressWarnings("unchecked")
public <T> T getExtension(Class<T> type, String name) {
for (ApplicationContext context : contexts) {
//该context是否包含name的bean
if (context.containsBean(name)) {
//获取该name对应的bean,如果是懒加载或者多实例的bean,此时会实例化name对应的bean
Object bean = context.getBean(name);
//如果obj的类型是typ或者其子类,与instance相同
if (type.isInstance(bean)) {
return (T) bean;
}
}
}
return null;
}
}
那么 Object object = objectFactory.getExtension(pt, property)这个方法先调用SpiExtensionFactory来实例化 如果不行,再使用SpringExtensionFactory来实例化。
dubbo的aop
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && wrapperClasses.size() > 0) {
for (Class<?> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
把原来的对象作为参数,注入到wrapper对象中,然后实例化出来。
为啥要这样做呢?因为它想在方法前后做点别的事,又不像影响原来的对象,这样就是实现了aop。
这里可能还是有些抽象,那么,我们就用Protocol为例子:
-
假设我们要获取ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(“dubbo”);
-
看看META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol内容:
registry=com.alibaba.dubbo.registry.integration.RegistryProtocol dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper mock=com.alibaba.dubbo.rpc.support.MockProtocol injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol rmi=com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol com.alibaba.dubbo.rpc.protocol.http.HttpProtocol com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol thrift=com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocol memcached=com.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocol redis=com.alibaba.dubbo.rpc.protocol.redis.RedisProtocol
-
那么我们首先获取到的就是com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol实例,然后type就是Protocol.class
接下来就会injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
这里filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper,listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper这两个类都是Protocol.class实现类,都有一个有参构造,且参数都是Protocol实例,那么此时instance就成了ProtocolFilterWrapper或者ProtocolFilterWrapper(wrapperClasses 无序)。
dubbo的Adaptive机制源码解析:
前面案例得知,利用getAdaptiveExtension方法获取,那么我们看看这个方法:
@SuppressWarnings("unchecked")
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;
}
...
private T createAdaptiveExtension() {
try {
//getAdaptiveExtensionClass()方法获取AdaptiveClass
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e);
}
}
private Class<?> getAdaptiveExtensionClass() {
//前面有解析,就是加载一些配置文件,并缓存下来。如果@Adaptive在类上,其实就是直接返回了。
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
//创建适配器类,给AdaptiveExtensionClass赋值,@Adaptive在方法上时走这里。
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
...
private Class<?> createAdaptiveExtensionClass() {
//获取class的代码
String code = createAdaptiveExtensionClassCode();
//获取类加载器
ClassLoader classLoader = findClassLoader();
//获取编译器AdaptiveCompiler
com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
//编译
return compiler.compile(code, classLoader);
}
这里有四步:
-
获取class的代码
-
获取类加载器
-
获取编译器AdaptiveCompiler
-
使用默认的JavassistCompiler编译
createAdaptiveExtensionClassCode()
先看看第一步createAdaptiveExtensionClassCode,这个代码很长,其实就是会编译一个类名为(接口名$Adaptive)的字符串,我们看看编译出来是怎样的:
package org.apache.dubbo.demo.example.eg19;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class FruitGranter$Adaptive implements org.apache.dubbo.demo.example.eg19.FruitGranter {
public org.apache.dubbo.demo.example.eg19.Fruit grant() {
throw new UnsupportedOperationException(
"The method public abstract org.apache.dubbo.demo.example.eg19.Fruit "
+ "org.apache.dubbo.demo.example.eg19.FruitGranter.grant() of interface "
+ "org.apache.dubbo.demo.example.eg19.FruitGranter is not adaptive method!");
}
public java.lang.String watering(org.apache.dubbo.common.URL arg0) {
if (arg0 == null) {
throw new IllegalArgumentException("url == null");
}
org.apache.dubbo.common.URL url = arg0;
String extName = url.getParameter("fruit.granter", "apple");
if (extName == null) {
throw new IllegalStateException(
"Failed to get extension (org.apache.dubbo.demo.example.eg19.FruitGranter) name "
+ "from url (" + url.toString() + ") use keys([fruit.granter])");
}
org.apache.dubbo.demo.example.eg19.FruitGranter extension =
(org.apache.dubbo.demo.example.eg19.FruitGranter) ExtensionLoader
.getExtensionLoader(org.apache.dubbo.demo.example.eg19.FruitGranter.class)
.getExtension(extName);
return extension.watering(arg0);
}
}
关于该生成的代码,我们主要要注意如下几个问题:
-
所有未使用@Adaptive注解标注的接口方法,默认都会抛出异常;
-
在使用@Adaptive注解标注的方法中,其参数中必须有一个参数类型为URL,或者其某个参数提供了某个方法,该方法可以返回一个URL对象;
-
在方法的实现中会通过URL对象获取某个参数对应的参数值,如果在接口的@SPI注解中指定了默认值,那么在使用URL对象获取参数值时,如果没有取到,就会使用该默认值;
-
最后根据获取到的参数值,在ExtensionLoader中获取该参数值对应的服务提供类对象,然后将真正的调用委托给该服务提供类对象进行;
-
在通过URL对象获取参数时,参数key获取的对应规则是,首先会从@Adaptive注解的参数值中获取,如果该注解没有指定参数名,那么就会默认将目标接口的类名转换为点分形式作为参数名,比如这里FruitGranter转换为点分形式就是fruit.granter。
compiler.compile(code, classLoader)
编译是AdaptiveCompiler去编译,配置文件有三个实现类,但是AdaptiveCompiler类上有@Adaptive注解,优先使用,我们来看看代码:
public Class<?> compile(String code, ClassLoader classLoader) {
Compiler compiler;
ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
String name = DEFAULT_COMPILER; // copy reference
if (name != null && name.length() > 0) {
compiler = loader.getExtension(name);
} else {
//走这里,默认name为null,默认是走配置文件中最后一个javassist=com.alibaba.dubbo.common.compiler.support.JavassistCompiler
compiler = loader.getDefaultExtension();
}
return compiler.compile(code, classLoader);
}
...
我们看看compiler配置文件:
adaptive=com.alibaba.dubbo.common.compiler.support.AdaptiveCompiler
jdk=com.alibaba.dubbo.common.compiler.support.JdkCompiler
javassist=com.alibaba.dubbo.common.compiler.support.JavassistCompiler
所以getDefaultExtension是javassist=com.alibaba.dubbo.common.compiler.support.JavassistCompiler
dubbo动态代理javassist和jdk区别:
生成动态代理类:都可以根据字节码生成class文件。
创建代理类,jdk更快
JAVAASSIST既可以通过动态代理也可以通过字节码生成class文件,执行代理类的方法,javassist更快。