摘要:如前所說(shuō),的目的是獲取一個(gè)指定實(shí)現(xiàn)類(lèi)的對(duì)象。接下來(lái)從子模塊下的包的開(kāi)始分析先來(lái)看這里繼承自類(lèi)。如沒(méi)有擴(kuò)展點(diǎn),在擴(kuò)展點(diǎn)實(shí)現(xiàn)調(diào)用該方法,并返回結(jié)果。前面已經(jīng)分析過(guò),就是使用讀取文件并緩存的反轉(zhuǎn)控制,就是從和里面提取對(duì)象賦值。
如前所說(shuō),Dubbo SPI的目的是獲取一個(gè)指定實(shí)現(xiàn)類(lèi)的對(duì)象。那么Dubbo是通過(guò)什么方式獲取的呢?其實(shí)是調(diào)用ExtensionLoader.getExtension(String name)實(shí)現(xiàn)。
具體實(shí)現(xiàn)途徑有三種:
①getExtensionLoader(Class
②getAdaptiveExtension() 獲取一個(gè)擴(kuò)展裝飾類(lèi)的對(duì)象,這個(gè)類(lèi)有一個(gè)規(guī)則,如果它沒(méi)有@Adaptive注解,就動(dòng)態(tài)創(chuàng)建一個(gè)裝飾類(lèi),例如Protocol$Adaptive對(duì)象。
③getExtension(String name) 獲取一個(gè)指定對(duì)象。
(1)分析ExtensionLoader.getExtensionLoader(Class
Dubbo的第一行代碼在哪里?
idea導(dǎo)入Dubbo源碼,在子模塊dubbo-demo-provider/src/test下有DemoProvider.java
package com.alibaba.dubbo.demo.provider; public class DemoProvider { public static void main(String[] args) { com.alibaba.dubbo.container.Main.main(args); } }
這里便是代碼的入口。
這里調(diào)到com.alibaba.dubbo.container.Main.java
package com.alibaba.dubbo.container; import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.common.extension.ExtensionLoader; import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.common.utils.ConfigUtils; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; /** * Main. (API, Static, ThreadSafe) * * @author william.liangf */ public class Main { public static final String CONTAINER_KEY = "dubbo.container"; public static final String SHUTDOWN_HOOK_KEY = "dubbo.shutdown.hook"; private static final Logger logger = LoggerFactory.getLogger(Main.class); private static final ExtensionLoaderloader = ExtensionLoader.getExtensionLoader(Container.class); private static volatile boolean running = true; public static void main(String[] args) { try { if (args == null || args.length == 0) { String config = ConfigUtils.getProperty(CONTAINER_KEY, loader.getDefaultExtensionName()); args = Constants.COMMA_SPLIT_PATTERN.split(config); } final List containers = new ArrayList (); for (int i = 0; i < args.length; i++) { containers.add(loader.getExtension(args[i])); } logger.info("Use container type(" + Arrays.toString(args) + ") to run dubbo serivce."); if ("true".equals(System.getProperty(SHUTDOWN_HOOK_KEY))) { Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { for (Container container : containers) { try { container.stop(); logger.info("Dubbo " + container.getClass().getSimpleName() + " stopped!"); } catch (Throwable t) { logger.error(t.getMessage(), t); } synchronized (Main.class) { running = false; Main.class.notify(); } } } }); } for (Container container : containers) { container.start(); logger.info("Dubbo " + container.getClass().getSimpleName() + " started!"); } System.out.println(new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss]").format(new Date()) + " Dubbo service server started!"); } catch (RuntimeException e) { e.printStackTrace(); logger.error(e.getMessage(), e); System.exit(1); } synchronized (Main.class) { while (running) { try { Main.class.wait(); } catch (Throwable e) { } } } } }
可以看到,Main類(lèi)中定義了一系列的靜態(tài)成員變量,其中:
private static final ExtensionLoaderloader = ExtensionLoader.getExtensionLoader(Container.class);
在Main類(lèi)初始化階段調(diào)用了上述第①條方式為Container創(chuàng)建擴(kuò)展點(diǎn)。
通過(guò)斷點(diǎn)跟進(jìn)getExtensionLoader方法,會(huì)進(jìn)行new ExtensionLoader
private ExtensionLoader(Class> type) { this.type = type; objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); }
可以看到,這里會(huì)進(jìn)一步調(diào)用getExtensionLoader方法,只是這次傳入的是ExtensionFactory.class。通過(guò)上面的代碼知道,等價(jià)于如下:
this.type = type; objectFactory = null;
執(zhí)行以上代碼完成了2個(gè)屬性的初始化:
1.每個(gè)ExtensionLoader都包含了2個(gè)值: type 和 objectFactory
Class> type;//構(gòu)造器初始化時(shí)要得到的接口名
ExtensionFactory objectFactory//構(gòu)造器初始化時(shí)設(shè)置為AdaptiveExtensionFactory,Dubbo內(nèi)部默認(rèn)的實(shí)現(xiàn)是SpiExtensionFactory和SpringExtensionFactory。
2.new 一個(gè)ExtensionLoader 存儲(chǔ)在ConcurrentMap
關(guān)于objectFactory
1.objectFactory就是ExtensionFactory,它也是通過(guò)ExtensionLoader.getExtensionLoader(ExtensionFactory.class)來(lái)實(shí)現(xiàn)的,但是它的objectFactory=null
2.objectFactory作用,它就是為dubbo的IOC提供所有對(duì)象。
(2)分析getAdaptiveExtension()
為什么要設(shè)計(jì)Adaptive?
Adaptive注解在類(lèi)和方法上有什么區(qū)別?
①注解在類(lèi)上,代表人工實(shí)現(xiàn)編碼,即實(shí)現(xiàn)了一個(gè)裝飾類(lèi),如ExtensionFactory。
②注解在方法上,代表自動(dòng)生成和編譯一個(gè)動(dòng)態(tài)的adaptive類(lèi),如Protocol$Adaptive。
接下來(lái)從子模塊dubbo-config-spring下的schema包的DubboNamespaceHandler開(kāi)始分析:
package com.alibaba.dubbo.config.spring.schema; import com.alibaba.dubbo.common.Version; import com.alibaba.dubbo.config.ApplicationConfig; import com.alibaba.dubbo.config.ConsumerConfig; import com.alibaba.dubbo.config.ModuleConfig; import com.alibaba.dubbo.config.MonitorConfig; import com.alibaba.dubbo.config.ProtocolConfig; import com.alibaba.dubbo.config.ProviderConfig; import com.alibaba.dubbo.config.RegistryConfig; import com.alibaba.dubbo.config.spring.AnnotationBean; import com.alibaba.dubbo.config.spring.ReferenceBean; import com.alibaba.dubbo.config.spring.ServiceBean; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; /** * DubboNamespaceHandler * * @author william.liangf * @export */ public class DubboNamespaceHandler extends NamespaceHandlerSupport { static { Version.checkDuplicate(DubboNamespaceHandler.class); } public void init() { registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true)); registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true)); registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true)); registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true)); registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true)); registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true)); registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true)); registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true)); registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false)); registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true)); } }
先來(lái)看
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
這里ServiceBean繼承自ServiceConfig類(lèi)。
public class ServiceConfigextends AbstractServiceConfig { private static final long serialVersionUID = 3033787999037024738L; private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); .... }
在這里通過(guò)getAdaptiveExtension()獲取protocol。
-->getAdaptiveExtension()//為cachedAdaptiveInstance賦值 -->createAdaptiveExtension() -->getAdaptiveExtensionClass()//該方法看出,如果是預(yù)定義的類(lèi)就直接返回,不然動(dòng)態(tài)生成適配類(lèi) -->getExtensionClasses()//為cachedClasses 賦值 -->loadExtensionClasses() -->loadFile(..) -->createAdaptiveExtensionClass()//自動(dòng)生成和編譯一個(gè)動(dòng)態(tài)的adpative類(lèi),這個(gè)類(lèi)是一個(gè)代理類(lèi) -->ExtensionLoader.getExtensionLoader (com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension() -->compiler.compile(code, classLoader) -->injectExtension()//作用:進(jìn)入IOC的反轉(zhuǎn)控制模式,實(shí)現(xiàn)了動(dòng)態(tài)注入
loadFile(..)方法的作用:把SPI配置文件(如META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol)的內(nèi)容,存儲(chǔ)在緩存變量里。使用了四個(gè)緩存變量。
①緩存包含Adaptive注解的類(lèi)
cachedAdaptiveClass 如果這個(gè)Class含有adaptive注解就賦值進(jìn)去,如ExtensionFactory有,而Protocol沒(méi)有。
②緩存無(wú)Adaptive注解的封裝類(lèi)
cachedWrapperClasses 只有當(dāng)該class無(wú)adaptive注解,并且構(gòu)造方法參數(shù)為目標(biāo)接口(type,如Protocol)類(lèi)型,如Protocol里的SPI就只有ProtocolFilterWrapper和ProtocolListenerWrapper能命中,如下例:
public class ProtocolFilterWrapper implements Protocol { private final Protocol protocol; public ProtocolFilterWrapper(Protocol protocol) { if (protocol == null) { throw new IllegalArgumentException("protocol == null"); } this.protocol = protocol; } 。。。 }
③cachedActivates 剩下的包含Activate注解的類(lèi)
④cachedName 剩下的類(lèi)存儲(chǔ)在該map中
在loadExtensionClasses()方法中,有三處loadFile()加載SPI文件:
private Map> 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 > extensionClasses = new HashMap >(); loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY); loadFile(extensionClasses, DUBBO_DIRECTORY); loadFile(extensionClasses, SERVICES_DIRECTORY); return extensionClasses; }
這里的三處loadFile()實(shí)際上起到真正作用的是第一個(gè):路徑為META-INF/dubbo/internal/,這個(gè)打開(kāi)dubbo.jar即可看到,這里仍然看com.alibaba.dubbo.rpc.Protocol這個(gè)SPI文件:
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
上面執(zhí)行compile時(shí),框架會(huì)自動(dòng)生成如下Protocol$Adpative類(lèi)代碼:
package com.alibaba.dubbo.rpc; import com.alibaba.dubbo.common.extension.ExtensionLoader; public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol { public void destroy() { throw new UnsupportedOperationException( "method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!"); } public int getDefaultPort() { throw new UnsupportedOperationException( "method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!"); } public com.alibaba.dubbo.rpc.Exporter export( com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException { if (arg0 == null) throw new IllegalArgumentException( "com.alibaba.dubbo.rpc.Invoker argument == null"); if (arg0.getUrl() == null) throw new IllegalArgumentException( "com.alibaba.dubbo.rpc.Invoker argument getUrl() == null"); com.alibaba.dubbo.common.URL url = arg0.getUrl(); String extName = (url.getProtocol() == null ? "dubbo" : url .getProtocol()); if (extName == null) throw new IllegalStateException( "Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader .getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class) .getExtension(extName); return extension.export(arg0);//自己執(zhí)行自己,說(shuō)明當(dāng)前類(lèi)是一個(gè)代理類(lèi) } public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException { if (arg1 == null) throw new IllegalArgumentException("url == null"); com.alibaba.dubbo.common.URL url = arg1; String extName = (url.getProtocol() == null ? "dubbo" : url .getProtocol()); if (extName == null) throw new IllegalStateException( "Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader .getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class) .getExtension(extName); return extension.refer(arg0, arg1);//自己執(zhí)行自己,說(shuō)明當(dāng)前類(lèi)是一個(gè)代理類(lèi) } }
其實(shí)就是根據(jù)如下模板生成的:
package <擴(kuò)展點(diǎn)接口所在包>; public class <擴(kuò)展點(diǎn)接口名>$Adpative implements <擴(kuò)展點(diǎn)接口> { public <有@Adaptive注解的接口方法>(<方法參數(shù)>) { if(是否有URL類(lèi)型方法參數(shù)?) 使用該URL參數(shù) else if(是否有方法類(lèi)型上有URL屬性) 使用該URL屬性 #if(獲取的URL == null) { throw new IllegalArgumentException("url == null"); } 根據(jù)@Adaptive注解上聲明的Key的順序,從URL獲致Value,作為實(shí)際擴(kuò)展點(diǎn)名。 如URL沒(méi)有Value,則使用缺省擴(kuò)展點(diǎn)實(shí)現(xiàn)。如沒(méi)有擴(kuò)展點(diǎn), throw new IllegalStateException("Fail to get extension"); 在擴(kuò)展點(diǎn)實(shí)現(xiàn)調(diào)用該方法,并返回結(jié)果。 } public <有@Adaptive注解的接口方法>(<方法參數(shù)>) { throw new UnsupportedOperationException("is not adaptive method!"); } }
總結(jié)起來(lái),Dubbo的所有對(duì)象都是通過(guò)ExtensionLoader獲取的,SPI是內(nèi)核。
(3)分析getExtension(String name)
為了進(jìn)一步分析代理類(lèi)的擴(kuò)展類(lèi)對(duì)象生成過(guò)程,將Protocol$Adpative類(lèi)手動(dòng)創(chuàng)建到dubbo源碼子模塊dubbo-demo下的dubbo-demo-provider中,test目錄下新建包c(diǎn)om.alibaba.dubbo.rpc。然后將上述代碼拷貝其中。
然后在getExtension(extName)這里設(shè)置斷點(diǎn):
通過(guò)斷點(diǎn)跟蹤,調(diào)用鏈如下:
-->getExtension(String name) //指定對(duì)象緩存在cachedInstances;get出來(lái)的對(duì)象可能是wrapper對(duì)象,例如protocol就是ProtocolFilterWrapper和ProtocolListenerWrapper其中一個(gè)。 -->createExtension(String name) -->getExtensionClasses() //前面已經(jīng)分析過(guò),就是使用loadFile讀取文件并緩存 -->injectExtension(T instance)//dubbo的IOC反轉(zhuǎn)控制,就是從spi和spring里面提取對(duì)象賦值。 -->objectFactory.getExtension(pt, property)//通過(guò)ExtensionFactory獲取extension,有兩種 -->①SpiExtensionFactory.getExtension(type, name) -->ExtensionLoader.getExtensionLoader(type) -->loader.getAdaptiveExtension() -->②SpringExtensionFactory.getExtension(type, name) -->context.getBean(name) -->injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance))//AOP的簡(jiǎn)單設(shè)計(jì),這個(gè)地方如果前面的wrapperClasses緩存不空,那么就會(huì)執(zhí)行這句代碼,如Protocol中只有Filter和Listener,通過(guò)使用ProtocolFilterWrapper或ProtocolListenerWrapper的構(gòu)造方法反射然后注入
通過(guò)上述分析,總結(jié)起來(lái)SPI getExtension()的執(zhí)行流程及設(shè)計(jì)模式如下:
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/68533.html
摘要:二注解該注解為了保證在內(nèi)部調(diào)用具體實(shí)現(xiàn)的時(shí)候不是硬編碼來(lái)指定引用哪個(gè)實(shí)現(xiàn),也就是為了適配一個(gè)接口的多種實(shí)現(xiàn),這樣做符合模塊接口設(shè)計(jì)的可插拔原則,也增加了整個(gè)框架的靈活性,該注解也實(shí)現(xiàn)了擴(kuò)展點(diǎn)自動(dòng)裝配的特性。 Dubbo擴(kuò)展機(jī)制SPI 前一篇文章《dubbo源碼解析(一)Hello,Dubbo》是對(duì)dubbo整個(gè)項(xiàng)目大體的介紹,而從這篇文章開(kāi)始,我將會(huì)從源碼來(lái)解讀dubbo再各個(gè)模塊的實(shí)...
摘要:對(duì)于這個(gè)矛盾的問(wèn)題,通過(guò)自適應(yīng)拓展機(jī)制很好的解決了。自適應(yīng)拓展機(jī)制的實(shí)現(xiàn)邏輯比較復(fù)雜,首先會(huì)為拓展接口生成具有代理功能的代碼。 1、背景 在 Dubbo 中,很多拓展都是通過(guò) SPI 機(jī)制進(jìn)行加載的,比如 Protocol、Cluster、LoadBalance 等。有時(shí),有些拓展并不想在框架啟動(dòng)階段被加載,而是希望在拓展方法被調(diào)用時(shí),根據(jù)運(yùn)行時(shí)參數(shù)進(jìn)行加載。這聽(tīng)起來(lái)有些矛盾。拓展未被...
摘要:今天我想聊聊的另一個(gè)很棒的特性就是它的可擴(kuò)展性。的擴(kuò)展機(jī)制在的官網(wǎng)上,描述自己是一個(gè)高性能的框架。接下來(lái)的章節(jié)中我們會(huì)慢慢揭開(kāi)擴(kuò)展機(jī)制的神秘面紗。擴(kuò)展擴(kuò)展點(diǎn)的實(shí)現(xiàn)類(lèi)。的定義在配置文件中可以看到文件中定義了個(gè)的擴(kuò)展實(shí)現(xiàn)。 摘要: 在Dubbo的官網(wǎng)上,Dubbo描述自己是一個(gè)高性能的RPC框架。今天我想聊聊Dubbo的另一個(gè)很棒的特性, 就是它的可擴(kuò)展性。 Dubbo的擴(kuò)展機(jī)制 在Dub...
摘要:簡(jiǎn)介全稱為,是一種服務(wù)發(fā)現(xiàn)機(jī)制。的本質(zhì)是將接口實(shí)現(xiàn)類(lèi)的全限定名配置在文件中,并由服務(wù)加載器讀取配置文件,加載實(shí)現(xiàn)類(lèi)。不過(guò),并未使用原生的機(jī)制,而是對(duì)其進(jìn)行了增強(qiáng),使其能夠更好的滿足需求。并未使用,而是重新實(shí)現(xiàn)了一套功能更強(qiáng)的機(jī)制。 1、SPI簡(jiǎn)介 SPI 全稱為 Service Provider Interface,是一種服務(wù)發(fā)現(xiàn)機(jī)制。SPI 的本質(zhì)是將接口實(shí)現(xiàn)類(lèi)的全限定名配置在文件中...
摘要:引語(yǔ)平時(shí)倒是聽(tīng)得很多又是啥別急我們來(lái)先看看面向接口編程的調(diào)用關(guān)系,來(lái)了解一下,和的相似和不同之處。理解先來(lái)一段官話的介紹全稱為,是內(nèi)置的一種服務(wù)提供發(fā)現(xiàn)機(jī)制聽(tīng)了一臉懵逼好的,我們結(jié)合圖片來(lái)理解一下。然后調(diào)用了內(nèi)部類(lèi)的方法。 引語(yǔ) 平時(shí)API倒是聽(tīng)得很多?SPI又是啥.別急我們來(lái)先看看面向接口編程的調(diào)用關(guān)系,來(lái)了解一下,API和SPI的相似和不同之處。 SPI理解 先來(lái)一段官話的介紹:S...
閱讀 1860·2021-11-24 09:39
閱讀 2613·2021-11-18 10:07
閱讀 3852·2021-08-31 09:40
閱讀 3593·2019-08-30 15:44
閱讀 2721·2019-08-30 12:50
閱讀 3732·2019-08-26 17:04
閱讀 1608·2019-08-26 13:49
閱讀 1352·2019-08-23 18:05