這篇文章主要講解了“Dubbo的SPI機(jī)制介紹以及Dubbo的IOC依賴注入實(shí)例”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Dubbo的SPI機(jī)制介紹以及Dubbo的IOC依賴注入實(shí)例”吧!
創(chuàng)新互聯(lián)專注于企業(yè)全網(wǎng)營銷推廣、網(wǎng)站重做改版、夏縣網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、成都h5網(wǎng)站建設(shè)、購物商城網(wǎng)站建設(shè)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)營銷網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為夏縣等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。
@Test public void test1(){ ExtensionLoaderloader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class); AdaptiveExt adaptiveExtension = loader.getExtension("dubbo"); URL url = URL.valueOf("test://localhost/test"); adaptiveExtension.echo("d", url); } public class DubboAdaptiveExt implements AdaptiveExt { // dubbo中有依賴AdaptiveExt類型的變量 private AdaptiveExt adaptiveExt; public void setAdaptiveExt(AdaptiveExt adaptiveExt) { this.adaptiveExt = adaptiveExt; } @Override public String echo(String msg, URL url) { System.out.println(this.adaptiveExt.echo(msg, url)); return "dubbo"; } }
// 此時(shí)ThriftAdaptiveExt上面是標(biāo)注了@Adaptive注解的 @Adaptive public class ThriftAdaptiveExt implements AdaptiveExt { @Override public String echo(String msg, URL url) { return "thrift"; } }
Spring的IOC中
,給生成的bean注入依賴,是調(diào)用context.getBean(name)
去獲得要注入的bean.Dubbo的IOC類似,它通過ExtensionFactory
類型的變量objectFactory
去dubbo中獲取bean,核心代碼objectFactory.getExtension(pt, property)
.下面先分析一下objectFactory
的創(chuàng)建過程.objectFactory
需要用到SpringExtensionFactory和SpiExtensionFactory
.先看一下ExtenionFactory
的實(shí)現(xiàn)類,如下圖.下面通過源碼分析objectFactory
的生成過程.
這里的getExtensionLoader()
詳細(xì)分析可以參見: Dubbo的SPI機(jī)制分析1-SPI加載class
ExtensionLoaderloader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class); public static ExtensionLoader getExtensionLoader(Class type) { // 刪去一些不必要的代碼,詳細(xì)分析可以看前面幾篇分析 // 從緩存中獲取與拓展類對應(yīng)的ExtensionLoader ExtensionLoader loader = (ExtensionLoader ) EXTENSION_LOADERS.get(type); if (loader == null) { // 若緩存未命中,則創(chuàng)建一個(gè)新的實(shí)例,創(chuàng)建新的實(shí)例時(shí)會走 EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader (type)); loader = (ExtensionLoader ) EXTENSION_LOADERS.get(type); } return loader; } private ExtensionLoader(Class> type) { this.type = type; // 這里的type是AdaptiveExt.class,所以會執(zhí)行后面的代碼,加載并創(chuàng)建SpiExtensionFactory和SpringExtensionFactory objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); }
public T getAdaptiveExtension() { Object instance = cachedAdaptiveInstance.get(); if (instance == null) { if (createAdaptiveInstanceError == null) { synchronized (cachedAdaptiveInstance) { instance = cachedAdaptiveInstance.get(); if (instance == null) { try { // 創(chuàng)建自適應(yīng)拓展代理類對象并放入緩存,這里創(chuàng)建的就是ExtensionFactory的自適應(yīng)拓展對象 instance = createAdaptiveExtension(); cachedAdaptiveInstance.set(instance); } catch (Throwable t) { // 拋異常 } } } } } return (T) instance; }
private T createAdaptiveExtension() { try { // 分為3步:1是創(chuàng)建自適應(yīng)拓展代理類Class對象,2是通過反射創(chuàng)建對象,3是給創(chuàng)建的對象按需依賴注入 return injectExtension((T) getAdaptiveExtensionClass().newInstance()); } catch (Exception e) { // 拋異常 } }
getExtensionClasses()
方法詳細(xì)分析可以參見: Dubbo的SPI機(jī)制分析1-SPI加載class
private Class> getAdaptiveExtensionClass() { // 這里前面文章已經(jīng)分析過了,它會去加載默認(rèn)目錄下的ExtensionFactory的實(shí)現(xiàn)類,總共有3個(gè),目錄是 // META-INF/dubbo/internal/,該目錄對應(yīng)兩個(gè)文件,文件內(nèi)容見下,由于AdaptiveExtensionFactory上面 // 標(biāo)注了@Adaptive注解,所以它優(yōu)先級最高,它就是ExtensionFactory的默認(rèn)實(shí)現(xiàn)類 getExtensionClasses(); // 如果有標(biāo)注了@Adaptive注解實(shí)現(xiàn)類,那么cachedAdaptiveClass不為空,直接返回 if (cachedAdaptiveClass != null) { // 這里直接返回,cachedAdaptiveClass = AdaptiveExtensionFactory.class return cachedAdaptiveClass; } // 不會再走這一步 return cachedAdaptiveClass = createAdaptiveExtensionClass(); }
文件1內(nèi)容: // 其中AdaptiveExtensionFactory上面標(biāo)注了@Adaptive注解 adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory 文件2內(nèi)容: spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory
@Adaptive public class AdaptiveExtensionFactory implements ExtensionFactory {
// 分析完了getAdaptiveExtensionClass(),它是返回AdaptiveExtensionFactory,接下來newInstance會調(diào)用它默認(rèn)的構(gòu)造方法 return injectExtension((T) getAdaptiveExtensionClass().newInstance()); @Adaptive public class AdaptiveExtensionFactory implements ExtensionFactory { // 里面維護(hù)SpringExtensionFactory和SpiExtensionFactory private final Listfactories; public AdaptiveExtensionFactory() { ExtensionLoader loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class); List list = new ArrayList (); for (String name : loader.getSupportedExtensions()) { // 分別給SpringExtensionFactory和SpiExtensionFactory創(chuàng)建對象并放入list中 list.add(loader.getExtension(name)); } factories = Collections.unmodifiableList(list); } }
// 上面已經(jīng)分析過了第一行代碼,這里面會創(chuàng)建ExtensionFactory類型的變量objectFactory,這里面維護(hù)了一個(gè)list, // list里面有SpringExtensionFactory和SpiExtensionFactory類型的實(shí)例,Dubbo的IOC獲取bean就是通過這兩個(gè)變量去獲取的 ExtensionLoaderloader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class); AdaptiveExt adaptiveExtension = loader.getExtension("dubbo"); public T getExtension(String name) { // 刪去一些代碼 if (instance == null) { synchronized (holder) { instance = holder.get(); if (instance == null) { // 創(chuàng)建拓展實(shí)例 instance = createExtension(name); holder.set(instance); } } } return (T) instance; }
private T createExtension(String name) { // 從配置文件中加載所有的拓展類,可得到“配置項(xiàng)名稱”到“配置類”的映射關(guān)系表 // 這里我們指定了名字dubbo,并不是通過getAdaptiveExtension方法去獲得自適應(yīng)拓展類,這點(diǎn)要區(qū)分 // 所以這里拿到的是com.alibaba.dubbo.demo.provider.adaptive.impl.DubboAdaptiveExt Class> clazz = getExtensionClasses().get(name); if (clazz == null) { throw findException(name); } try { // 也是嘗試先從緩存獲取,獲取不到通過反射創(chuàng)建一個(gè)并放到緩存中 T instance = (T) EXTENSION_INSTANCES.get(clazz); if (instance == null) { // 這里直接通過反射創(chuàng)建DubboAdaptiveExt的實(shí)例,然后給他依賴注入 EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance()); instance = (T) EXTENSION_INSTANCES.get(clazz); } // 依賴注入 injectExtension(instance); return instance; } }
private T injectExtension(T instance) { // 這里為了排版好看,刪去一些異常捕捉拋出代碼 // objectFactory就是我們前面分析的,它里面維護(hù)了SpringExtensionFactory和SpiExtensionFactory類型的實(shí)例 if (objectFactory != null) { // 遍歷DubboAdaptiveExt實(shí)例的所有方法,尋找set開頭且參數(shù)為1個(gè),且方法權(quán)限為public的方法 for (Method method : instance.getClass().getMethods()) { if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 && Modifier.isPublic(method.getModifiers())) { // 獲取參數(shù)類型,這里是AdaptiveExt.class Class> pt = method.getParameterTypes()[0]; // 獲取屬性名,這里是adaptiveExt String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : ""; // 獲取容器中AdaptiveExt.class類型的名字為adaptiveExt的實(shí)例 Object object = objectFactory.getExtension(pt, property); // 獲取之后通過反射賦值 if (object != null) { method.invoke(instance, object); } } } } return instance; }
@Adaptive public class AdaptiveExtensionFactory implements ExtensionFactory { private final Listfactories; @Override public T getExtension(Class type, String name) { // 遍歷factory中所有的ExtensionFactory,先從SpiExtensionFactory中獲取,獲取不到在去Spring容器中獲取 for (ExtensionFactory factory : factories) { T extension = factory.getExtension(type, name); if (extension != null) { return extension; } } return null; } }
這里獲取自適應(yīng)拓展可以參考: Dubbo的SPI機(jī)制分析2-Adaptive詳解
public class SpiExtensionFactory implements ExtensionFactory { @Override publicT getExtension(Class type, String name) { if (type.isInterface() && type.isAnnotationPresent(SPI.class)) { ExtensionLoader loader = ExtensionLoader.getExtensionLoader(type); if (!loader.getSupportedExtensions().isEmpty()) { // 先看SpiExtensionFactory怎么獲取,它是通過getAdaptiveExtension()去自適應(yīng)獲取,根本 // 沒有用到name,所以這里返回ThriftAdaptiveExt的實(shí)例 return loader.getAdaptiveExtension(); } } return null; } }
public class SpringExtensionFactory implements ExtensionFactory { // 可以看到Spring是先根據(jù)名字去取,取不到再根據(jù)類型去取 @Override publicT getExtension(Class type, String name) { for (ApplicationContext context : contexts) { if (context.containsBean(name)) { Object bean = context.getBean(name); if (type.isInstance(bean)) { return (T) bean; } } } for (ApplicationContext context : contexts) { try { return context.getBean(type); } } return null; } }
// 所以這段代碼輸出:thrift @Test public void test1(){ ExtensionLoaderloader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class); AdaptiveExt adaptiveExtension = loader.getExtension("dubbo"); URL url = URL.valueOf("test://localhost/test"); adaptiveExtension.echo("d", url); }
/** * 測試通過URL依賴注入,將ThriftAdaptiveExt類上面的注解注釋掉,同時(shí)給AdaptiveExt方法加上注解@Adaptive("t") */ @Test public void test5(){ ExtensionLoaderloader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class); Map map = new HashMap<>(); // t這個(gè)key就是根據(jù)@Adaptive("t")定的,兩者要一致 map.put("t", "cloud"); URL url = new URL("", "", 1, map); AdaptiveExt adaptiveExtension = loader.getExtension("dubbo"); adaptiveExtension.echo(" ", url); }
上述代碼輸出spring cloud,創(chuàng)建完DubboAdaptiveExt的實(shí)例給其注入依賴時(shí),調(diào)用injectExtension(instance)
,因?yàn)闆]有了@Adaptive標(biāo)注的類,所以需要Dubbo自己生成自適應(yīng)拓展代理類Class,生成過程可以參考: Dubbo的SPI機(jī)制分析2-Adaptive詳解.生成的代理類中有這樣一句關(guān)鍵代碼: String extName = url.getParameter("t", "dubbo")
,因?yàn)閡rl中有這個(gè)t參數(shù),所以最后會調(diào)用cloud所對應(yīng)的SpringCloudAdaptiveExt的echo方法,輸出spring cloud.
感謝各位的閱讀,以上就是“Dubbo的SPI機(jī)制介紹以及Dubbo的IOC依賴注入實(shí)例”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Dubbo的SPI機(jī)制介紹以及Dubbo的IOC依賴注入實(shí)例這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!