日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

dubboSPI机制浅谈

發布時間:2025/3/8 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 dubboSPI机制浅谈 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2019獨角獸企業重金招聘Python工程師標準>>>

本文重點講述SPI機制,從jdk和dubbo

1、jdk spi機制

2、dubbo spi實現

首先spi是什么?

SPI是為某個接口尋找服務實現的機制。為了實現在模塊裝配的時候能不在程序里動態指明,這就需要一種服務發現機制。

其次java spi是怎么找到實現類的?

java spi和所有實現接口的廠商有一個俗稱的約定,只要將META-INF/services文件夾下生成一個和抽象類全名稱(路徑+類名稱)相同的配置文件,那么廠商的jar包只要在工程路徑下就能找到實現類。這種方式主要是解決不同廠商不同實現類的加載問題。在不修改java文件的情況下,如何才能夠定位到不同的實現類。

JDK的spi機制有一個缺點,就是如果多個廠商的spi實現的jar包都在路徑下,那么就要加載所有的實現類,這樣很浪費資源。dubbo中每一種接口都有很多種實現,如果使用jdk這種方式自然做不到優雅的根據一個接口來獲得該接口的實現。dubbo的目標就是:根據你配置的name獲取某一個特定的接口實現,沒有用到的其他接口實現就不能被實例化,免得浪費。因此,dubbo就按照SPI機制的原理自己實現了一套擴展機制。為實現dubbo的擴展機制,dubbo的SPI做到了一下三個方面。

1?可以方便的獲取某一個想要的擴展實現,java的SPI機制就沒有提供這樣的功能
2?對于擴展實現IOC???依賴注入功能

3?對擴展采用裝飾器模式進行功能增強,類似AOP實現的功能

dubbo的SPI實現具體如下。

首先定義一個SPI注解類

@Documented
@Retention
(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SPI {

/**
? ? * 缺省擴展點名。
? ? */
String value() default "";

}

dubbo里面很多的接口都打了SPI注解,這些注解的實現要從一下三個文件夾下去尋找實現。

META-INF/dubbo/internal/ ? //dubbo內部實現的各種擴展都放在了這個目錄了

META-INF/dubbo

/META-INF/services/



文件里面的內容全部都是key-value的形式存在。dubbo的各種接口有很多類型的實現。拿Protocol舉例,它的實現:DubboProtocol InjvmProtocolHessianProtocol WebServiceProtocol等等。dubbo的擴展機制如何去查找你的實現類,并實現調用的呢?

ExtensionLoader<T>
拿ServiceConfig<T>中的這兩個變量舉例子。
private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
這兩個變量最終生成的既不是接口也不是具體的實現類,而是一個接口適配器類。這個適配器類動態的生成的,如下所示的代碼:

package?com.alibaba.dubbo.rpc; import?com.alibaba.dubbo.common.extension.ExtensionLoader; public?class?ProxyFactory$Adpative?implements?com.alibaba.dubbo.rpc.ProxyFactory?{ public?java.lang.Object?getProxy(com.alibaba.dubbo.rpc.Invoker?arg0)?throws?com.alibaba.dubbo.rpc.Invoker?{ 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.getParameter("proxy",?"javassist"); if(extName?==?null)?throw?new?IllegalStateException("Fail?to?get?extension(com.alibaba.dubbo.rpc.ProxyFactory)?name?from?url("?+?url.toString()?+?")?use?keys([proxy])"); //根據url的信息去獲取真實的實現類 com.alibaba.dubbo.rpc.ProxyFactory?extension?=?(com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName); return?extension.getProxy(arg0); } public?com.alibaba.dubbo.rpc.Invoker?getInvoker(java.lang.Object?arg0,?java.lang.Class?arg1,?com.alibaba.dubbo.common.URL?arg2)?throws?java.lang.Object?{ if?(arg2?==?null)?throw?new?IllegalArgumentException("url?==?null"); com.alibaba.dubbo.common.URL?url?=?arg2; String?extName?=?url.getParameter("proxy",?"javassist"); if(extName?==?null)?throw?new?IllegalStateException("Fail?to?get?extension(com.alibaba.dubbo.rpc.ProxyFactory)?name?from?url("?+?url.toString()?+?")?use?keys([proxy])"); com.alibaba.dubbo.rpc.ProxyFactory?extension?=?(com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName); return?extension.getInvoker(arg0,?arg1,?arg2); } }

首先,我們來看適配器類是如何生成

com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName);


第一步:通過proxyFactory.class類型生成一個ExtensionLoader<T>實例。

public?static?<T>?ExtensionLoader<T>?getExtensionLoader(Class<T>?type)?{ ExtensionLoader<T>?loader?=?(ExtensionLoader<T>)?EXTENSION_LOADERS.get(type); if?(loader?==?null)?{每個定義的spi的接口都會構建一個ExtensionLoader實例,存儲在EXTENSION_LOADERS EXTENSION_LOADERS.putIfAbsent(type,?new?ExtensionLoader<T>(type));loader?=?(ExtensionLoader<T>)?EXTENSION_LOADERS.get(type); } return?loader;}


第二步:創建Adaptive實例,放入數組cachedAdaptiveInstance中。

public?T?getAdaptiveExtension()?{Object?instance?=?cachedAdaptiveInstance.get(); if?(instance?==?null)?{ if(createAdaptiveInstanceError?==?null)?{ synchronized?(cachedAdaptiveInstance)?{instance?=?cachedAdaptiveInstance.get(); if?(instance?==?null)?{ try?{//創建Adaptive實例,放入數組cachedAdaptiveInstance中。instance?=?createAdaptiveExtension(); cachedAdaptiveInstance.set(instance);}?catch?(Throwable?t)?{ createAdaptiveInstanceError?=?t; throw?new?IllegalStateException("fail?to?create?adaptive?instance:?"?+?t.toString(),?t);}}}} else?{ throw?new?IllegalStateException("fail?to?create?adaptive?instance:?"?+?createAdaptiveInstanceError.toString(),?createAdaptiveInstanceError);}} return?(T)?instance; }private?T?createAdaptiveExtension()?{ try?{ return?injectExtension((T)?getAdaptiveExtensionClass().newInstance());}?catch?(Exception?e)?{ throw?new?IllegalStateException("Can?not?create?adaptive?extenstion?"?+?type?+?",?cause:?"?+?e.getMessage(),?e);} }private?Class<?>?createAdaptiveExtensionClass()?{ //生成類適配器,String?code?=?createAdaptiveExtensionClassCode(); ClassLoader?classLoader?=?findClassLoader();com.alibaba.dubbo.common.compiler.Compiler?compiler?=?ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();//編譯這個類適配器為class文件 return?compiler.compile(code,?classLoader); } //?此方法已經getExtensionClasses方法同步過。 private?Map<String,?Class<?>>?loadExtensionClasses()?{//先讀取SPI注解的value值,有值作為默認擴展實現的key 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<String,?Class<?>>?extensionClasses?=?new?HashMap<String,?Class<?>>();//讀取三個文件夾下的文件,將key-class放置到extensionClasses中loadFile(extensionClasses,?DUBBO_INTERNAL_DIRECTORY);loadFile(extensionClasses,?DUBBO_DIRECTORY);loadFile(extensionClasses,?SERVICES_DIRECTORY); return?extensionClasses; } private?void?loadFile(Map<String,?Class<?>>?extensionClasses,?String?dir)?{ //獲取文件路徑?目錄+type名稱String?fileName?=?dir?+?type.getName();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?url?=?urls.nextElement();try?{BufferedReader?reader?=?new?BufferedReader(new?InputStreamReader(url.openStream(),?"utf-8"));try?{String?line?=?null;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?=?line.substring(0,?i).trim();line?=?line.substring(i?+?1).trim();}if?(line.length()?>?0)?{ //讀取到類Class<?>?clazz?=?Class.forName(line,?true,?classLoader); //判斷實現類是否實現了type接口if?(!?type.isAssignableFrom(clazz))?{throw?new?IllegalStateException("Error?when?load?extension?class(interface:?"?+type?+?",?class?line:?"?+?clazz.getName()?+?"),?class?"?+?clazz.getName()?+?"is?not?subtype?of?interface.");} //類中是否有方法打了Adaptive注解if?(clazz.isAnnotationPresent(Adaptive.class))?{ //將打了Adaptive注解的類放置到cachedAdaptiveClass?中去。if(cachedAdaptiveClass?==?null)?{cachedAdaptiveClass?=?clazz;}else?if?(!?cachedAdaptiveClass.equals(clazz))?{throw?new?IllegalStateException("More?than?1?adaptive?class?found:?"+?cachedAdaptiveClass.getClass().getName()+?",?"?+?clazz.getClass().getName());}}?else?{//判斷該是否有實現類是否存在入參為接口的構造器clazz.getConstructor(type);Set<Class<?>>?wrappers?=?cachedWrapperClasses;if?(wrappers?==?null)?{cachedWrapperClasses?=?new?ConcurrentHashSet<Class<?>>();wrappers?=?cachedWrapperClasses;}//按照裝飾器的角色將該類加進來wrappers.add(clazz);}?//?end?of?while?urls}}?catch?(Throwable?t)?{logger.error("Exception?when?load?extension?class(interface:?"?+type?+?",?description?file:?"?+?fileName?+?").",?t);} }

適配器中發現這個實現類也是由這個方法生成extension?=?(com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName)


//創建擴展類 instance?=?createExtension(name); private?T?createExtension(String?name)?{ //加載類Class<?>?clazz?=?getExtensionClasses().get(name);if?(clazz?==?null)?{throw?findException(name);}try?{//從容器中獲取是否存在T?instance?=?(T)?EXTENSION_INSTANCES.get(clazz);if?(instance?==?null)?{//容器中不存在,則按照類-實例對的形式放置到容器中EXTENSION_INSTANCES.putIfAbsent(clazz,?(T)?clazz.newInstance());//獲取該實例數據對instance?=?(T)?EXTENSION_INSTANCES.get(clazz);}//set注入參數injectExtension(instance);//獲取包裝器類。class?com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper???class?com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapperSet<Class<?>>?wrapperClasses?=?cachedWrapperClasses;if?(wrapperClasses?!=?null?&&?wrapperClasses.size()?>?0)?{for?(Class<?>?wrapperClass?:?wrapperClasses)?{ //將實例對更新為有包裝器類的實例。?????????????instance?=?injectExtension((T)?wrapperClass.getConstructor(type).newInstance(instance));}}return?instance;}?catch?(Throwable?t)?{throw?new?IllegalStateException("Extension?instance(name:?"?+?name?+?",?class:?"?+type?+?")??could?not?be?instantiated:?"?+?t.getMessage(),?t);} }



dubbo的SPI擴展機制,使得我們給出url就能動態的去獲取真實的實現類。獲得到真實的實現類,是實現功能的第一步。下面我們來看看spring如何加載到dubbo解析器類,并將dubbo功能收入囊下的。未完待續。


參考文獻

http://m.blog.csdn.net/blog/u010311445/41577235





轉載于:https://my.oschina.net/zjItLife/blog/530923

總結

以上是生活随笔為你收集整理的dubboSPI机制浅谈的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。