Dubbo的SPI可扩展机制的源码分析

         Dubbo的代码的版本是2.7.0

       在看Dubbo源码的时候,总是出现下面的代码去加载一个类。 

          然后,看一下ProxyFactory这个类名上了加了一个注解。,

           

       这里以ServiceConfig里的ProxyFactory为例,这里就是今天所要讲的Dubbo的SPI机制, 通过ExtensionLoader这个类去实现的。

             

         这里最主要的的ETENTION_LOADERS是保存扩展点类和对应ExtensionLoader的的映射, EXTENSION_INSTANCES是缓存扩展类和反射实例化的映射,

       getExtensionLoader函数,出入扩展类,如果没有,则放入IINSTENSION_LOADERS里面。映射的value是ExtensionLoader对象,可以看到新建的ExtensioLoader的扩展类

不是ExtensionFactory,则还是会调用ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()方法,来加载adaptive的扩展类。

    然后,getAdaptiveExtension的,通过cacheAdaptiveExtension的get方法,  这里可以二次判断来防止的并发的操作。

          因为开始都为空,createAdativeExtension的函数创建一个扩展点的对象。

        然后调用getAdaptiveExtensionClass函数去加载扩展类,

    首先是通过  getExtensionClasses函数,获取扩展点的类

    因为开始都是空的,所以出事调用时候,会调用loadExtensionClasses函数,去加载所有的扩展类,

  

         前面是获取@SPI注解的值,然后loadDirectoy方法去加载项目下 META-INF/dubbo/internal/,META-INF/dubbo/, META-INF/services/

           这里就可以看出META-IN这下面的是都是扩展点的配置。

  

          这里是利用classloade加载class的,还调用loaderResource就是I利用Class.forName去加载对应的类了。

    加载完所有的扩展类后, 初始cacheAdaptiveClass为空,则创建createAdaptiveExtensionClass方法。

   这里首先看一下,createAdapativeExtensionClassCode动态生成的代码,从下面可以看出它生成的类名=扩展类+$Adaptive,实现扩展类的接口,并且找到ClassLoader,并且加载ExtensionLoader的Complier,去编译生成的代码,并且加载到JVM,得到一个Class.

package org.apache.dubbo.rpc;
import org.apache.dubbo.common.extension.ExtensionLoader;

public class ProxyFactory$Adaptive implements org.apache.dubbo.rpc.ProxyFactory {
private static final org.apache.dubbo.common.logger.Logger logger = org.apache.dubbo.common.logger.LoggerFactory.getLogger(ExtensionLoader.class);
private java.util.concurrent.atomic.AtomicInteger count = new java.util.concurrent.atomic.AtomicInteger(0);

public org.apache.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, org.apache.dubbo.common.URL arg2) throws org.apache.dubbo.rpc.RpcException {
if (arg2 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg2;
String extName = url.getParameter("proxy", "javassist");
if(extName == null) throw new IllegalStateException("Fail to get extension(org.apache.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])");
org.apache.dubbo.rpc.ProxyFactory extension = null;
 try {
extension = (org.apache.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
}catch(Exception e){
if (count.incrementAndGet() == 1) {
logger.warn("Failed to find extension named " + extName + " for type org.apache.dubbo.rpc.ProxyFactory, will use default extension javassist instead.", e);
}
extension = (org.apache.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension("javassist");
}
return extension.getInvoker(arg0, arg1, arg2);
}
public java.lang.Object getProxy(org.apache.dubbo.rpc.Invoker arg0, boolean arg1) 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();
String extName = url.getParameter("proxy", "javassist");
if(extName == null) throw new IllegalStateException("Fail to get extension(org.apache.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])");
org.apache.dubbo.rpc.ProxyFactory extension = null;
 try {
extension = (org.apache.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
}catch(Exception e){
if (count.incrementAndGet() == 1) {
logger.warn("Failed to find extension named " + extName + " for type org.apache.dubbo.rpc.ProxyFactory, will use default extension javassist instead.", e);
}
extension = (org.apache.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension("javassist");
}
return extension.getProxy(arg0, arg1);
}
public java.lang.Object getProxy(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();
String extName = url.getParameter("proxy", "javassist");
if(extName == null) throw new IllegalStateException("Fail to get extension(org.apache.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])");
org.apache.dubbo.rpc.ProxyFactory extension = null;
 try {
extension = (org.apache.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
}catch(Exception e){
if (count.incrementAndGet() == 1) {
logger.warn("Failed to find extension named " + extName + " for type org.apache.dubbo.rpc.ProxyFactory, will use default extension javassist instead.", e);
}
extension = (org.apache.dubbo.rpc.ProxyFactory).getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension("javassist");
}
return extension.getProxy(arg0);
}
}

 总结:

       本次对Dubbo 的SPI机制的一点粗略的理解。

原文地址:https://www.cnblogs.com/xjz1842/p/9876210.html