Dubbo配置參數(shù)詳解-stub

Dubbo配置參數(shù)詳解-stub

Dubbo是一個由阿里開源的服務(wù)治理框架瞧挤,筆者的公司重度使用Dubbo。Dubbo開源這么多年棋枕,配置項(xiàng)已經(jīng)非常豐富材部,了解各個配置項(xiàng)的作用也變得非常重要,本系列將從源代碼的角度分析Dubbo目前的最新版本(2.7.4)各個常用的配置項(xiàng)的具體含義以及是怎么起作用的杏节。

畫外音:目前Dubbo在開源中國舉辦的2019年度最受歡迎中國開源軟件中排名第3名唬渗,支持Dubbo的朋友可以去投票哇。2019年度最受歡迎中國開源軟件

stub是啥奋渔?

stub:存根镊逝,rmi需要存根(stub)和骨架(skeleton),stub用于客戶端嫉鲸,skeleton用于服務(wù)器端撑蒜。簡單來說,你調(diào)用provider玄渗,相關(guān)的服務(wù)方不是要提供給你一個jar包嗎座菠,那個jar包就是存根。
畫外音:使用過WebService的同學(xué)應(yīng)該很清楚

stub有啥用藤树?

一般的存根都是只有接口辈灼,不包含實(shí)現(xiàn)。但是dubbo提供的這個stub作用有點(diǎn)類似于攔截器也榄,它可以在調(diào)用正在的provider之前或之后對請求及結(jié)果進(jìn)行處理。

stub怎么使用司志?

存根主要有兩種使用方式甜紫,一種是服務(wù)提供者寫好,并隨jar包一起提供給調(diào)用方骂远,這種方式可以用來做前置驗(yàn)證囚霸,另外一種方式是調(diào)用方自己寫,這可以用來對結(jié)果進(jìn)行處理激才;

如果是服務(wù)方提供拓型,Stub一般都是定義在接口的同包目錄下额嘿,并且使用InterfaceName+Stub的命名方式,這時調(diào)用方只要設(shè)置stub="true"就可以使用了劣挫。

/**
 * @description:
 * @author: chengang6
 * @create: 2019/5/10 10:38
 **/
public interface HelloDubboService {
    String say();
    String hello();
    String post(String key);
}
/**
 * @description: Stub必須實(shí)現(xiàn)相同的接口册养,且跟接口在同一個目錄
 * @author: chengang6
 * @create: 2020/1/7 10:37
 **/
public class HelloDubboServiceStub implements HelloDubboService {

    private HelloDubboService helloDubboService;

    //必須提供這種類似代理的構(gòu)造函數(shù),否則會報(bào)錯
    public HelloDubboServiceStub(HelloDubboService helloDubboService) {
        this.helloDubboService = helloDubboService;
    }

    @Override
    public String say() {
        return ">>>>>>>>Stub>>>>say";
    }

    @Override
    public String hello() {
        // 此代碼在客戶端執(zhí)行, 你可以在客戶端做ThreadLocal本地緩存压固,或預(yù)先驗(yàn)證參數(shù)是否合法球拦,等等
        try {
            return helloDubboService.hello();
        } catch (Exception e) {
            // 你可以容錯,可以做任何AOP攔截事項(xiàng)
            return "容錯數(shù)據(jù)";
        }
    }

    @Override
    public String post(String key) {
        return ">>>>>>>>Stub>>>>post";
    }
}
    //只要配置stub=true就可以使用存根了
    @Reference(stub = "true")
    private HelloDubboService helloDubboService;

也可以在@Service中配置stub="true"帐我,這樣就算Consumer端么有配置stub坎炼,也會強(qiáng)制Consumer端執(zhí)行Stub

@Service(stub = "true")
public class HelloDubboServiceImpl implements HelloDubboService {

Consumer端也可以自定義Stub,此時不需要遵循InterfaceName+Stub的命名方式拦键,但需要把完整的類名寫在參數(shù)中谣光,比如

    @Reference(stub = "com.example.dubboconsumer.stub.MyStub")
    private HelloDubboService helloDubboService;

stub的命名規(guī)則是什么樣的?

在Reference初始化的時候會判斷是否設(shè)置了stub芬为,如果設(shè)置了該參數(shù)會在AbstractInterfaceConfig類的checkStubAndLocal方法中判斷該參數(shù)的有效性

    /**
     * Legitimacy check of stub, note that: the local will deprecated, and replace with <code>stub</code>
     *
     * @param interfaceClass for provider side, it is the {@link Class} of the service that will be exported; for consumer
     *                       side, it is the {@link Class} of the remote service interface
     */
    void checkStubAndLocal(Class<?> interfaceClass) {
        if (ConfigUtils.isNotEmpty(local)) {
            Class<?> localClass = ConfigUtils.isDefault(local) ?
                    ReflectUtils.forName(interfaceClass.getName() + "Local") : ReflectUtils.forName(local);
            verify(interfaceClass, localClass);
        }
        if (ConfigUtils.isNotEmpty(stub)) {
            Class<?> localClass = ConfigUtils.isDefault(stub) ?
                    ReflectUtils.forName(interfaceClass.getName() + "Stub") : ReflectUtils.forName(stub);
            verify(interfaceClass, localClass);
        }
    }
    private void verify(Class<?> interfaceClass, Class<?> localClass) {
        if (!interfaceClass.isAssignableFrom(localClass)) {
            throw new IllegalStateException("The local implementation class " + localClass.getName() +
                    " not implement interface " + interfaceClass.getName());
        }

        try {
            //Check if the localClass a constructor with parameter who's type is interfaceClass
            ReflectUtils.findConstructor(localClass, interfaceClass);
        } catch (NoSuchMethodException e) {
            throw new IllegalStateException("No such constructor \"public " + localClass.getSimpleName() +
                    "(" + interfaceClass.getName() + ")\" in local implementation class " + localClass.getName());
        }
    }

可以看到Dubbo除了提供Stub萄金,還可以使用Local這種方式,但是這種方式Dubbo已經(jīng)不推薦使用碳柱;
如果stub="true"捡絮,Dubbo將會在相同接口的包下尋找InterfaceName+Stub這個類,否則將會根據(jù)全限定名尋找莲镣;并且Stub中必須有一個將接口作為形參的構(gòu)造函數(shù)福稳,否則報(bào)錯;

stub是如何生效的瑞侮?

Dubbo在為reference生成代理類的時候的圆,都會調(diào)用StubProxyFactoryWrapper判斷該reference是否需要使用stub,如果是則直接返回stub

public class StubProxyFactoryWrapper implements ProxyFactory {
        @SuppressWarnings({"unchecked", "rawtypes"})
    public <T> T getProxy(Invoker<T> invoker) throws RpcException {
        T proxy = proxyFactory.getProxy(invoker);
        if (GenericService.class != invoker.getInterface()) {
            URL url = invoker.getUrl();
            String stub = url.getParameter(STUB_KEY, url.getParameter(LOCAL_KEY));
            if (ConfigUtils.isNotEmpty(stub)) {
                Class<?> serviceType = invoker.getInterface();
                if (ConfigUtils.isDefault(stub)) {
                    if (url.hasParameter(STUB_KEY)) {
                        stub = serviceType.getName() + "Stub";
                    } else {
                        stub = serviceType.getName() + "Local";
                    }
                }
                try {
                    Class<?> stubClass = ReflectUtils.forName(stub);
                    if (!serviceType.isAssignableFrom(stubClass)) {
                        throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + serviceType.getName());
                    }
                    try {
                        Constructor<?> constructor = ReflectUtils.findConstructor(stubClass, serviceType);
                        proxy = (T) constructor.newInstance(new Object[]{proxy});
                        //export stub service
                        URLBuilder urlBuilder = URLBuilder.from(url);
                        if (url.getParameter(STUB_EVENT_KEY, DEFAULT_STUB_EVENT)) {
                            urlBuilder.addParameter(STUB_EVENT_METHODS_KEY, StringUtils.join(Wrapper.getWrapper(proxy.getClass()).getDeclaredMethodNames(), ","));
                            urlBuilder.addParameter(IS_SERVER_KEY, Boolean.FALSE.toString());
                            try {
                                export(proxy, (Class) invoker.getInterface(), urlBuilder.build());
                            } catch (Exception e) {
                                LOGGER.error("export a stub service error.", e);
                            }
                        }
                    } catch (NoSuchMethodException e) {
                        throw new IllegalStateException("No such constructor \"public " + stubClass.getSimpleName() + "(" + serviceType.getName() + ")\" in stub implementation class " + stubClass.getName(), e);
                    }
                } catch (Throwable t) {
                    LOGGER.error("Failed to create stub implementation class " + stub + " in consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", cause: " + t.getMessage(), t);
                    // ignore
                }
            }
        }
        return proxy;
    }
    
}

問題

如果stub是在服務(wù)端配置半火,而沒有在consumer端配置越妈,并且consumer啟動在前,這時StubProxyFactoryWrapper將會判斷reference不需要stub钮糖,當(dāng)provider啟動后梅掠,就算@Service配置了stub="true",consumer也不會調(diào)用stub。

總結(jié):

  • stub一般是服務(wù)提供方提供店归,并隨jar包一起提供給consumer;
  • 可以設(shè)置@Service(stub="true")阎抒,這樣就能強(qiáng)制consumer端使用stub;
  • stub是在consumer端執(zhí)行的消痛,可以做前置驗(yàn)證且叁,這樣可以過濾非法請求,提高性能秩伞;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末逞带,一起剝皮案震驚了整個濱河市欺矫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌展氓,老刑警劉巖穆趴,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異带饱,居然都是意外死亡毡代,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門勺疼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來教寂,“玉大人,你說我怎么就攤上這事执庐±腋” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵轨淌,是天一觀的道長迂烁。 經(jīng)常有香客問我,道長递鹉,這世上最難降的妖魔是什么盟步? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮躏结,結(jié)果婚禮上却盘,老公的妹妹穿的比我還像新娘。我一直安慰自己媳拴,他們只是感情好黄橘,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著屈溉,像睡著了一般塞关。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上子巾,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天帆赢,我揣著相機(jī)與錄音,去河邊找鬼线梗。 笑死椰于,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的缠导。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼溉痢,長吁一口氣:“原來是場噩夢啊……” “哼僻造!你這毒婦竟也來了憋他?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤髓削,失蹤者是張志新(化名)和其女友劉穎竹挡,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體立膛,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡揪罕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了宝泵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片好啰。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖儿奶,靈堂內(nèi)的尸體忽然破棺而出框往,到底是詐尸還是另有隱情,我是刑警寧澤闯捎,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布椰弊,位于F島的核電站,受9級特大地震影響瓤鼻,放射性物質(zhì)發(fā)生泄漏秉版。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一茬祷、第九天 我趴在偏房一處隱蔽的房頂上張望清焕。 院中可真熱鬧,春花似錦牲迫、人聲如沸耐朴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽筛峭。三九已至,卻和暖如春陪每,著一層夾襖步出監(jiān)牢的瞬間影晓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工檩禾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留挂签,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓盼产,卻偏偏與公主長得像饵婆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子戏售,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容