dubbo 扩展点
Dubbo SPI机制在Dubbo中应用非常广泛,例如监听、拦截、协议、通讯、序列化等等无处不在,这样做的好处在于可以做定制化开发,可以根据实际情况做相应的扩展。 Dubbo扩展点分为:静态扩展点、自适应扩展点和激活扩展点
静态扩展点
静态扩展点简单来说就是将key和value(实现类)加载到map中,然后通过key获取value来实现扩展,示例代码:
public class SpringbootDubboClientApplication {
public static void main(String[] args) {
/**
* 1.加载指定路径下的SPI扩展点的实现,缓存到HashMap中,key为文件中的key,value为class
* 2.通过key获取实现类,即getExtension("dubbo"),dubbo为key
*/
Protocol protocol=ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("dubbo");
}
}
那SPI扩展点是如何加载的呢?我们来看下getExtension("dubbo")中的源码是如何实现的
public class ExtensionLoader<T> {
...
public T getExtension(String name) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
} else if ("true".equals(name)) {
return this.getDefaultExtension();
} else {
Holder<Object> holder = this.getOrCreateHolder(name);
Object instance = holder.get();
if (instance == null) {
synchronized(holder) {
instance = holder.get();
if (instance == null) {
//此处会创建Extension
instance = this.createExtension(name);
holder.set(instance);
}
}
}
return instance;
}
}
...
}
上面的getExtension(Stringname)做了一些判断和缓存,我们重点关注createExtension(name),接下来我们继续跟进去看
public class ExtensionLoader<T> {
...
private T createExtension(String name) {
//此处就是加载扩展点,然后通过name获取到class
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);
Set<Class<?>> wrapperClasses = this.cachedWrapperClasses;
Class wrapperClass;
if (CollectionUtils.isNotEmpty(wrapperClasses)) {
for(Iterator var5 = wrapperClasses.iterator(); var5.hasNext(); instance = this.injectExtension(wrapperClass.getConstructor(this.type).newInstance(instance))) {
wrapperClass = (Class)var5.next();
}
}
return instance;
} catch (Throwable var7) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " + this.type + ") couldn't be instantiated: " + var7.getMessage(), var7);
}
}
}
...
}
上面通过this.getExtensionClasses()来加载到扩展点的实现,我们继续看看他究竟是如何实现加载的
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) {
//进行ExtensionClass的加载
classes = this.loadExtensionClasses();
this.cachedClasses.set(classes);
}
}
}
return classes;
}
上面又是做一些判断和缓存之类的操作,我们继续跟进this.loadExtensionClasses()中
private Map<String, Class<?>> loadExtensionClasses() {
this.cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap();
//type为上面的Protocol.class,下面代码就是加载具体文件的信息,即key和value
this.loadDirectory(extensionClasses, "META-INF/dubbo/internal/", this.type.getName());
this.loadDirectory(extensionClasses, "META-INF/dubbo/internal/", this.type.getName().replace("org.apache", "com.alibaba"));
this.loadDirectory(extensionClasses, "META-INF/dubbo/", this.type.getName());
this.loadDirectory(extensionClasses, "META-INF/dubbo/", this.type.getName().replace("org.apache", "com.alibaba"));
this.loadDirectory(extensionClasses, "META-INF/services/", this.type.getName());
this.loadDirectory(extensionClasses, "META-INF/services/", this.type.getName().replace("org.apache", "com.alibaba"));
return extensionClasses;
}
文件的目录结构:
resources
META-INF
dubbo
internal
org.apache.dubbo.rpc.Protocol(文件名和接口名Protocol必须一致)
--org.apache.dubbo.rpc.Protocol中的内容
filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=org.apache.dubbo.rpc.support.MockProtocol
--我们通过getExtension("dubbo")就可以获取到DubboProtocol这个class
dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol
injvm=org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol
rmi=org.apache.dubbo.rpc.protocol.rmi.RmiProtocol
hessian=org.apache.dubbo.rpc.protocol.hessian.HessianProtocol
http=org.apache.dubbo.rpc.protocol.http.HttpProtocol
org.apache.dubbo.rpc.protocol.webservice.WebServiceProtocol
thrift=org.apache.dubbo.rpc.protocol.thrift.ThriftProtocol
memcached=org.apache.dubbo.rpc.protocol.memcached.MemcachedProtocol
redis=org.apache.dubbo.rpc.protocol.redis.RedisProtocol
rest=org.apache.dubbo.rpc.protocol.rest.RestProtocol
registry=org.apache.dubbo.registry.integration.RegistryProtocol
qos=org.apache.dubbo.qos.protocol.QosProtocolWrapper
接下来进行依赖注入创建实现类DubboProtocol
private T createExtension(String name) {
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);
}
//将获取到的class进行依赖注入
this.injectExtension(instance);
Set<Class<?>> wrapperClasses = this.cachedWrapperClasses;
Class wrapperClass;
if (CollectionUtils.isNotEmpty(wrapperClasses)) {
for(Iterator var5 = wrapperClasses.iterator(); var5.hasNext(); instance = this.injectExtension(wrapperClass.getConstructor(this.type).newInstance(instance))) {
wrapperClass = (Class)var5.next();
}
}
return instance;
} catch (Throwable var7) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " + this.type + ") couldn't be instantiated: " + var7.getMessage(), var7);
}
}
}
private T injectExtension(T instance) {
try {
if (this.objectFactory != null) {
Method[] var2 = instance.getClass().getMethods();
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
Method method = var2[var4];
if (this.isSetter(method) && method.getAnnotation(DisableInject.class) == null) {
Class<?> pt = method.getParameterTypes()[0];
if (!ReflectUtils.isPrimitives(pt)) {
try {
String property = this.getSetterProperty(method);
Object object = this.objectFactory.getExtension(pt, property);
if (object != null) {
//通过反射调用生成实现类
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;
}
以上就是dubbo的静态扩展点,下面我们可以试着来实现自己的扩展,例如Protocol的扩展
首先我们创建一个MyProtoco类继承Protocol
public class MyProtocol implements Protocol {
@Override
public int getDefaultPort() {
//我们将默认端口改为6666以验证我们上面的分析是否正确
return 6666;
}
@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
return null;
}
@Override
public <T> Invoker<T> refer(Class<T> aClass, URL url) throws RpcException {
return null;
}
@Override
public void destroy() {
}
}
接着我们在resources目录下的META-INF/dubbo或者META-INF/services或者META-INF/dubbo/internal下创建和Protocol接口相同接口名的文件即org.apache.dubbo.rpc.Protocol
文件中的内容为myprotocol=com.gupaoedu.dubbo.springbootdubboclient.MyProtocol
其中key可以随便定义,value为我们自定义的实现类即上面的com.gupaoedu.dubbo.springbootdubboclient.MyProtocol
接下来我们写个main方法来实践一下
public class MyProtocolDemo {
public static void main(String[] args) {
Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("myprotocol");
System.out.println(protocol.getDefaultPort());
}
}
运行结果为6666,说明我们上面的分析是正确的,所以我们可以利用静态扩展点来实现我们一些业务需求的扩展
自适应扩展点
dubbo中的自适应扩展点简单来说就是类似于运作是加载具体的实现,由于dubbo是基于url驱动的,所以自适应扩展点利用从url中获取信息来动态的加载具体扩展实现类,下面我们先来看一个数据库驱动实现的简单案例来做介绍:
首先我们创建一个带@SPI注解的接口
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.SPI;
@SPI
public interface Driver {
String buildConnection(URL url);
}
该接口的自适应实现类如下:
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class AdaptiveDriver implements Driver {
@Override
public String buildConnection(URL url) {
if (url == null) {
throw new RuntimeException("url为空");
}
//dubbo基于url驱动,从url中获取key
String driverName = url.getParameter("driver");
if (driverName == null) {
throw new RuntimeException("driverName为空");
}
//此处是我们上面讲的自适应扩展点,所以需要在META-INF/dubbo下配置一个文件并设置好我们所需要key和目标实现类全限定名
Driver driver = ExtensionLoader.getExtensionLoader(Driver.class).getExtension(driverName);
return driver.buildConnection(url);
}
}
接着我们创建一个类似加载器的接口和实现类
import org.apache.dubbo.common.URL;
public interface DriverLoad {
String loadDriver(URL url);
}
实现类接口如下:
import org.apache.dubbo.common.URL;
public class DriverLoadFactory implements DriverLoad {
Driver driver;
//通过set方法进行构造注入自适应实现类,即AdaptiveDriver
public void setDriver(Driver driver) {
this.driver = driver;
}
@Override
public String loadDriver(URL url) {
//调用自适应实现类方法
String s = driver.buildConnection(url);
return s;
}
}
最后我们写一个测试方法来模拟自适应扩展点的整个流程
import org.apache.dubbo.common.URL;
import java.util.HashMap;
import java.util.Map;
public class Demo {
public static void main(String[] args) {
Map<String, String> param = new HashMap<>();
param.put("driver", "mysql");
//生成url并设置key和value值
URL url = new URL("dubbo","127.0.0.2",8080,param);
DriverLoadFactory oracleDriver = new DriverLoadFactory();
Driver driver = new AdaptiveDriver();
//通过构造方法将自适应实现类注入到加载器中
oracleDriver.setDriver(driver);
//进行加载
oracleDriver.loadDriver(url);
}
}
配置文件中的内容为:
resources:
META-INF:
dubbo:
com.stu.dubbo.MysqlDriverImpl (最终实现类)
package com.stu.dubbo;
import org.apache.dubbo.common.URL;
public class MysqlDriverImpl implements Driver {
@Override
public String buildConnection(URL url) {
return "mysql";
}
}
启动成功输出结果为mysql
上面实例的流程总结为通过自适应扩展实现类注入到加载器中,然后进行加载,调用自适应扩展实现,然后从url中获取key,再通过静态扩展点加载到具体实现类,最后调用目标方法。
下面我们来分析源码中是如何实现自适应扩展点的
步骤一
public static void main(String[] args) {
//自适应扩展点getAdaptiveExtension()
Compiler compiler = ExtensionLoader.getExtensionLoader(Compiler.class).getAdaptiveExtension();
System.out.println(compiler);
}
步骤二 上面这段代码就是所谓的自适应扩展点,运行后可以看到输出结果为:
org.apache.dubbo.common.compiler.support.AdaptiveCompiler@182decdb
步骤三 说明getAdaptiveExtension是生成自适应扩展的入口,接下来我们来看看里面如何实现的
public class ExtensionLoader<T> {
。。。
public T getAdaptiveExtension() {
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {
if (createAdaptiveInstanceError == null) {
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
//此处创建自适应扩展点
instance = createAdaptiveExtension();
//将自适应扩展点存放到cacheAdaptiveInstance中,并返回instance
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
}
}
}
} else {
throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
}
}
return (T) instance;
}
。。。
}
步骤四 进入createAdaptiveExtension()方法
public class ExtensionLoader<T> {
。。。
private T createAdaptiveExtension() {
try {
//此处的getAdaptiveExtensionClass进行创建并获取自适应扩展点
//injectExtension将获取的扩展点进行实例化并进行依赖注入
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
}
}
。。。
}
步骤五 我们先看看getAdaptiveExtensionClass如何实现
public class ExtensionLoader<T> {
。。。
private Class<?> getAdaptiveExtensionClass() {
//加载指定路径下的文件
getExtensionClasses();
//cachedAdaptvieClass, @Adaptive这个表示在类上的
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
//在方法级别
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
。。。
}
步骤六 进入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;
}
步骤七
进入loadExtensionClasses()中
private Map<String, Class<?>> loadExtensionClasses() {
cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap<>();
//读取resouces目录下/META-INF/internal的文件org.apache.dubbo.common.compiler.Compiler
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
return extensionClasses;
}
此处的type为Compile.class,读取到文件org.apache.dubbo.common.compiler.Compiler,文件中有一下内容:
//自适应扩展点
adaptive=org.apache.dubbo.common.compiler.support.AdaptiveCompiler
//具体的实现
jdk=org.apache.dubbo.common.compiler.support.JdkCompiler
javassist=org.apache.dubbo.common.compiler.support.JavassistCompiler
此时loadDirectory会将具体实现加载到extensionClasses中,将AdativeCompiler存放到步骤三中的cachedAdaptiveClass,然后步骤五判断是否为空,不为空就返回,最终一层层返回Demo中,现在
重点来看下,什么时候存放到cacheAdaptiveClass中的,我们继续从loadDirectory中进入
步骤八 进入loadDirectory
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {
String fileName = dir + type;
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 resourceURL = urls.nextElement();
//进行资源的加载
loadResource(extensionClasses, classLoader, resourceURL);
}
}
} catch (Throwable t) {
logger.error("Exception occurred when loading extension class (interface: " +
type + ", description file: " + fileName + ").", t);
}
}
步骤九 进入loadResource方法中
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
try {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {
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为文件中的key,即Adaptive
name = line.substring(0, i).trim();
//line为实现类的全限定名
line = line.substring(i + 1).trim();
}
if (line.length() > 0) {
//进行class的加载
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);
}
}
}
}
} catch (Throwable t) {
logger.error("Exception occurred when loading extension class (interface: " +
type + ", class file: " + resourceURL + ") in " + resourceURL, t);
}
}
步骤十 加载class
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
if (!type.isAssignableFrom(clazz)) {
throw new IllegalStateException("Error occurred when loading extension class (interface: " +
type + ", class line: " + clazz.getName() + "), class "
+ clazz.getName() + " is not subtype of interface.");
}
if (clazz.isAnnotationPresent(Adaptive.class)) {
//终于迎来曙光,这里判断clazz即AdaptiveCompiler上是否有自适应注解
//我们查看AdaptiveCompiler可以知道是有该注解的,所以此时会将clazz存放到cacheAdaptiveClass中
cacheAdaptiveClass(clazz);
} else if (isWrapperClass(clazz)) {
cacheWrapperClass(clazz);
} else {
clazz.getConstructor();
if (StringUtils.isEmpty(name)) {
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 (ArrayUtils.isNotEmpty(names)) {
cacheActivateClass(clazz, names[0]);
for (String n : names) {
cacheName(clazz, n);
saveInExtensionClass(extensionClasses, clazz, name);
}
}
}
}
现在我们再想想一开始我们Demo中输出的AdaptiveComipler就可以了解到是怎么回事。
接下来我们来看下自适应扩展点是如何在程序运行是调用具体的实现类
public static void main(String[] args) {
//自适应扩展点getAdaptiveExtension()
Compiler compiler = ExtensionLoader.getExtensionLoader(Compiler.class).getAdaptiveExtension();
//调用编译的方法
compiler.compile("randomString", ClassLoader.getSystemClassLoader());
}
进入到compile方法中
//此处注解就是我们上面判断类上是否有注解的逻辑
@Adaptive
public class AdaptiveCompiler implements Compiler {
private static volatile String DEFAULT_COMPILER;
public AdaptiveCompiler() {
}
public static void setDefaultCompiler(String compiler) {
DEFAULT_COMPILER = compiler;
}
public Class<?> compile(String code, ClassLoader classLoader) {
ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
//默认进来为空,即调用默认实现
String name = DEFAULT_COMPILER;
Compiler compiler;
if (name != null && name.length() > 0) {
compiler = (Compiler)loader.getExtension(name);
} else {
//默认实现
compiler = (Compiler)loader.getDefaultExtension();
}
return compiler.compile(code, classLoader);
}
}
进入默认实现中
public T getDefaultExtension() {
//这个方法上面已经分析了,获取扩展点,设置cacheDefaultName,
getExtensionClasses();
if (StringUtils.isBlank(cachedDefaultName) || "true".equals(cachedDefaultName)) {
return null;
}
//若cacheDefaultName不为空,则执行该方法,该方法是上面所将的静态扩展点
//就是通过key为cacheDefaultName获取具体的实现类
return getExtension(cachedDefaultName);
}
下面我们看下cacheDefaultName是如何赋值的,首先进入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() {
//该方法就是进行cacheDefaultName的赋值
cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap<>();
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
return extensionClasses;
}
进入cacheDefaultExtensionName方法中
private void cacheDefaultExtensionName() {
//type为Compiler.class,该类上有标这@SPI("javassist")注解
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation != null) {
//Compiler("javassist")
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) {
//重点来了,cacheDefaultName进行赋值,cacheDefaultName = "javassist"
cachedDefaultName = names[0];
}
}
}
}
接着我们通过javassist从上面的的文件中找到org.apache.dubbo.common.compiler.support.JavassistCompiler,这样就实现了自适应扩展点的具体实现,这也是自适应扩展点中的其中一种,即类级别的自适应扩展点,还有另外一种实现是方法级别的自适应扩展点,类击毙的自适应扩展点是在
类上表明@Adaptive,那我们可以猜想方法级别是不是在方法上标注@Adaptive,下面让我们一起来
看看方法级别的实现:
private Class<?> getAdaptiveExtensionClass() {
//加载指定路径下的文件
getExtensionClasses();
//cachedAdaptvieClass, @Adaptive这个表示在类上的
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
//在方法级别
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
上面代码可以看出是区分方法类级别还是方法级别的@Adaptive注解,createAdaptiveExtensionClass方法进行方法级别创建自适应扩展点
private Class<?> createAdaptiveExtensionClass() {
//生成动态代理类的字符串
String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
//ClassLoader
ClassLoader classLoader = findClassLoader();
//获取compiler自适应扩展点,类级别的,默认Javasssit
org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.
getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).
getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
上面这段代码主要做了四件事:
1.生成动态代理类的字符串
2.获取CLassLoader
3.获取Compiler的自适应扩展点
4.调用compile方法进行编译代理类字符串
我们看看代理类字符串是怎样的,通过运行下面这段代码
Protocol protocol = ExtensionLoad.getExtensionLoad(Protocol.class).getAdaptiveExtension()
通过在生成动态代理类字符串这里断点可以得到code
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!");
}
//Protocol上export方法标注@Adaptive
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");
org.apache.dubbo.common.URL url = arg0.getUrl();
//通过url获取协议,默认为dubbo
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);
}
//Protocol上refer方法标注@Adaptive
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);
}
}
上面生成代码的逻辑有点复杂,如果想要深入了解可以参考dubbo官网进行学习:http://dubbo.apache.org/zh-cn/docs/source_code_guide/adaptive-extension.html
最后我们来看下激活扩展点,激活扩展点有点像@ConditionOnClass,默认不激活,通过配置进行启动该扩展点,我们来看下下面这段代码:
public static void main(String[] args) {
URL url = new URL("http", "127.0.0.1", 0);
//激活cache扩展点
url.addParameter("cache", "cache");
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(url, "cache");
}
上面这段代码运行结果filters中是有CacheFilter这个类的,但是如果去掉激活cache这段代码后,运行结果就没有CacheFilter了,我们看CacheFilter类
@Activate(
group = {"consumer", "provider"},
value = {"cache"}
)
public class CacheFilter implements Filter {
该类有@Activate注解,表明该类是激活扩展点,value值如果配置了cache则激活该类,这是激活扩展点的简单分析
总结:
以上就是关于dubbo的静态扩展点、自适应扩展点和激活扩展点的自我理解,里面可能有些地方分析的不透彻或者不清楚请见谅,如有不懂可以留言一起分析