Dubbo的SPI可扩展机制的源码分析
在看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机制的一点粗略的理解。