前言
前面兩篇文章對(duì)dubbo SPI的使用和原理進(jìn)行簡(jiǎn)單的講解既荚,大家應(yīng)該對(duì)dubbo SPI有了認(rèn)識(shí)穆律。在 Dubbo 中读慎,很多拓展都是通過(guò) SPI 機(jī)制進(jìn)行加載的怕品,比如 Protocol野舶、Cluster易迹、LoadBalance 等。
現(xiàn)在我們?cè)賮?lái)回顧一下dubbo SPI的簡(jiǎn)單使用平道,代碼如下:
// 1睹欲、先獲取 extensionLoader
ExtensionLoader<Robot> extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class);
// 2、根據(jù)名稱獲取對(duì)應(yīng)的擴(kuò)展點(diǎn)instance
Robot optimusPrime = extensionLoader.getExtension("optimusPrime");
// 3一屋、調(diào)用對(duì)應(yīng)擴(kuò)展點(diǎn)instance的方法
optimusPrime.sayHello();
這段代碼演示了dubbo SPI的使用窘疮,但是有一個(gè)問(wèn)題,擴(kuò)展點(diǎn)對(duì)應(yīng)的實(shí)現(xiàn)類不能在程序運(yùn)行時(shí)動(dòng)態(tài)指定冀墨,就是extensionLoader.getExtension
方法寫(xiě)死了擴(kuò)展點(diǎn)對(duì)應(yīng)的實(shí)現(xiàn)類闸衫,不能在程序運(yùn)行期間根據(jù)運(yùn)行時(shí)參數(shù)進(jìn)行動(dòng)態(tài)改變。
對(duì)于這個(gè)矛盾的問(wèn)題诽嘉,就有引入我們今天要將的Adaptive
蔚出,就是dubbo 的自適應(yīng)機(jī)制。Dubbo 通過(guò)自適應(yīng)拓展機(jī)制很好的解決了虫腋。我們首先看一下如果是我們身冬,怎么解決這個(gè)矛盾,下面給出示例:
- 這里先定義一個(gè)接口岔乔,取名叫
AdaptiveExt
酥筝, 這里需要加一個(gè)com.alibaba.dubbo.common.extension.SPI
的注解
@SPI
public interface AdaptiveExt {
String echo(String msg, URL url);
}
這里的URL
類為dubbo里面的URL
- 接著創(chuàng)建一個(gè)實(shí)現(xiàn)類
SpringAdaptiveExtImpl
,按照dubbo SPI 配置雏门,配置好
public class SpringAdaptiveExtImpl implements AdaptiveExt {
@Override
public String echo(String msg, URL url) {
return "spring";
}
}
- 重點(diǎn)來(lái)了嘿歌,這一步我們解決擴(kuò)展點(diǎn)對(duì)應(yīng)的實(shí)現(xiàn)類不能在程序運(yùn)行時(shí)動(dòng)態(tài)指定的問(wèn)題,這里我們自己編寫(xiě)一個(gè)
AdaptiveExt
自適應(yīng)實(shí)現(xiàn)類茁影,如下:
public class AdaptiveExtProxy implements AdaptiveExt{
@Override
public String echo(String msg, URL url) {
// 非空檢查
if (url == null) {
throw new IllegalArgumentException("url == null");
}
// 1宙帝、從 URL 中獲取 AdaptiveExt 名稱
String name = url.getParameter("adaptive.ext");
if (name == null ) {
throw new IllegalArgumentException("name == null");
}
// 2、調(diào)用 SPI 動(dòng)態(tài)加載具體的 AdaptiveExt
AdaptiveExt adaptiveExt = ExtensionLoader
.getExtensionLoader(AdaptiveExt.class)
.getExtension(name);
// 3募闲、調(diào)用具體的方法
return adaptiveExt.echo(msg, url);
}
}
AdaptiveExtProxy
其實(shí)是一個(gè)代理類步脓,AdaptiveExtProxy
所代理的對(duì)象是在echo
方法中通過(guò)SPI加載得到的,echo
方法主要做了三件事情:
- 從 URL 中獲取
AdaptiveExt
名稱 - 通過(guò) SPI 加載具體的
AdaptiveExt
實(shí)現(xiàn)類 - 調(diào)用目標(biāo)方法
- 進(jìn)行測(cè)試,測(cè)試代碼如下:
@Test
public void test() {
URL url = URL.valueOf("test://localhost/test?adaptive.ext=spring");
AdaptiveExt adaptiveExt = new AdaptiveExtProxy();
System.out.println(adaptiveExt.echo("e", url));
}
輸出結(jié)果:
spring
Process finished with exit code 0
到這里靴患,我們自己基本上解決了上面所說(shuō)的矛盾仍侥。大家大致知道 dubbo SPI 擴(kuò)展點(diǎn)對(duì)應(yīng)的實(shí)現(xiàn)類,在程序運(yùn)行期間根據(jù)運(yùn)行時(shí)參數(shù)進(jìn)行動(dòng)態(tài)改變的解決方案了鸳君。就是設(shè)置一個(gè)代理類农渊,代理類根據(jù)程序運(yùn)行期間URL的參數(shù),動(dòng)態(tài)加載響應(yīng)的實(shí)現(xiàn)類并代理或颊。
dubbo Adaptive的使用
剛才我們簡(jiǎn)單講了dubbo的自適應(yīng)拓展機(jī)制是啥砸紊,現(xiàn)在我們開(kāi)學(xué)習(xí)dubbo 自適應(yīng)機(jī)制的學(xué)習(xí)。dubbo 自適應(yīng)機(jī)制的使用是通過(guò)注解的方式囱挑,注解為com.alibaba.dubbo.common.extension.Adaptive
醉顽。直接上代碼示例:
- 首先定義一個(gè)接口,名稱為
AdaptiveExt
平挑,使用SPI
和Adaptive
修飾:
@SPI
public interface AdaptiveExt {
@Adaptive
String echo(String msg, URL url);
}
- 創(chuàng)建三個(gè)實(shí)現(xiàn)類徽鼎,分別為
DubboAdaptiveExtImpl
、SpringAdaptiveExtImpl
和SpringBootAdaptiveExtImpl
public class DubboAdaptiveExtImpl implements AdaptiveExt {
@Override
public String echo(String msg, URL url) {
return "dubbo";
}
}
public class SpringAdaptiveExtImpl implements AdaptiveExt {
@Override
public String echo(String msg, URL url) {
return "spring";
}
}
public class SpringBootAdaptiveExtImpl implements AdaptiveExt{
@Override
public String echo(String msg, URL url) {
return "spring boot";
}
}
- 接著在META-INF/dubbo文件夾下創(chuàng)建一個(gè)文件弹惦,名稱為
Robot
的全限定名com.hui.wang.dubbo.learn.dubbo.adaptive.AdaptiveExt
否淤,內(nèi)容如下:
dubbo=com.hui.wang.dubbo.learn.dubbo.adaptive.DubboAdaptiveExtImpl
spring=com.hui.wang.dubbo.learn.dubbo.adaptive.SpringAdaptiveExtImpl
springboot=com.hui.wang.dubbo.learn.dubbo.adaptive.SpringBootAdaptiveExtImpl
到這里,示例的基本代碼搭建完成棠隐,現(xiàn)在開(kāi)始進(jìn)入使用和測(cè)試
- 在URL里面指定參數(shù)石抡,代碼為:
@Test
public void test1() {
ExtensionLoader<AdaptiveExt> extExtensionLoader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
AdaptiveExt adaptiveExt = extExtensionLoader.getAdaptiveExtension();
URL url = URL.valueOf("test://localhost/test?adaptive.ext=spring");
System.out.println(adaptiveExt.echo("d", url));
}
打印結(jié)果為:
spring
可以看出,當(dāng)URL中參數(shù)指定相應(yīng)的擴(kuò)展點(diǎn)實(shí)現(xiàn)類名稱后助泽,就可以根據(jù)名稱動(dòng)態(tài)的調(diào)用響應(yīng)名稱的實(shí)現(xiàn)類啰扛。
- 配置
Adaptive
注解的value
值,代碼如下:
@SPI
public interface AdaptiveExt {
@Adaptive(value = {"myAdaptiveName"})
String echo(String msg, URL url);
}
測(cè)試代碼:
@Test
public void test4() {
ExtensionLoader<AdaptiveExt> extExtensionLoader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
AdaptiveExt adaptiveExt = extExtensionLoader.getAdaptiveExtension();
URL url = URL.valueOf("test://localhost/test?myAdaptiveName=spring");
System.out.println(adaptiveExt.echo("d", url));
}
打印結(jié)果為:
spring
在方法上打上@Adaptive
注解嗡贺,注解中的value
與鏈接中的參數(shù)的key
一致隐解,鏈接中的key
對(duì)應(yīng)的value
就是spi中的name
,獲取相應(yīng)的實(shí)現(xiàn)類。
3.@Adaptive
注解使用在實(shí)現(xiàn)類上诫睬,代碼如下:
@Adaptive
public class DubboAdaptiveExtImpl implements AdaptiveExt {
@Override
public String echo(String msg, URL url) {
return "dubbo";
}
}
測(cè)試代碼:
@Test
public void test4() {
ExtensionLoader<AdaptiveExt> extExtensionLoader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
AdaptiveExt adaptiveExt = extExtensionLoader.getAdaptiveExtension();
URL url = URL.valueOf("test://localhost/test?myAdaptiveName=spring");
System.out.println(adaptiveExt.echo("d", url));
}
打印結(jié)果為:
dubbo
這里可以看到實(shí)現(xiàn)類上有@Adaptive
注解后煞茫,默認(rèn)調(diào)用該類進(jìn)行調(diào)用。
到這里基本上就是dubbo 自適應(yīng)機(jī)制的使用摄凡,即@Adaptive
注解的使用续徽,在下一篇我們將介紹@Adaptive
注解背后的源碼實(shí)現(xiàn)