dubbox註解的一個坑

  我和我同事Daniel排查的一個問題,原文是我同事Daniel寫的,我作了些修改了補充。git

  咱們dubbox的provider端有不少service開發時沒有考慮到冪等問題,因而只能暫時關掉dubbo的重試功能。github

  dubbo自帶的配置中有一個reties是能夠配置重試次數的,官方文檔上說默認兩次,設置成0能夠關閉重試。這種配置在使用xml 方式配置時是沒有問題的,然而用註解就比較坑。微信

  

  上圖是同事寫的使用註解的測試類截圖,有沒有發現0是灰色的?看看編譯後的.class文件:ide

  

  爲何呢,咱們看這個註解的源碼:oop

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface Reference {

   ...

    int retries() default 0;

   ...

}

  這個註解有個默認值0,編譯的時候被編譯器發現,因而優化掉了。而調用的時候:測試

  

  從註解中反射找reties,若是沒找到就取默認值2,因而就形成了一個現象,只要不設置0就沒問題,0就會等同於2。上圖的完整方法:優化

    public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
        List<Invoker<T>> copyinvokers = invokers;
        checkInvokers(copyinvokers, invocation);
        int len = getUrl().getMethodParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1;
        if (len <= 0) {
            len = 1;
        }
        // retry loop.
        RpcException le = null; // last exception.
        List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyinvokers.size()); // invoked invokers.
        Set<String> providers = new HashSet<String>(len);
        for (int i = 0; i < len; i++) {
            //重試時,進行從新選擇,避免重試時invoker列表已發生變化.
            //注意:若是列表發生了變化,那麼invoked判斷會失效,由於invoker示例已經改變
            if (i > 0) {
                checkWheatherDestoried();
                copyinvokers = list(invocation);
                //從新檢查一下
                checkInvokers(copyinvokers, invocation);
            }
            Invoker<T> invoker = select(loadbalance, invocation, copyinvokers, invoked);
            invoked.add(invoker);
            RpcContext.getContext().setInvokers((List)invoked);
            try {
                Result result = invoker.invoke(invocation);
                if (le != null && logger.isWarnEnabled()) {
                    logger.warn("Although retry the method " + invocation.getMethodName()
                            + " in the service " + getInterface().getName()
                            + " was successful by the provider " + invoker.getUrl().getAddress()
                            + ", but there have been failed providers " + providers 
                            + " (" + providers.size() + "/" + copyinvokers.size()
                            + ") from the registry " + directory.getUrl().getAddress()
                            + " on the consumer " + NetUtils.getLocalHost()
                            + " using the dubbo version " + Version.getVersion() + ". Last error is: "
                            + le.getMessage(), le);
                }
                return result;
            } catch (RpcException e) {
                if (e.isBiz()) { // biz exception.
                    throw e;
                }
                le = e;
            } catch (Throwable e) {
                le = new RpcException(e.getMessage(), e);
            } finally {
                providers.add(invoker.getUrl().getAddress());
            }
        }
        throw new RpcException(le != null ? le.getCode() : 0, "Failed to invoke the method "
                + invocation.getMethodName() + " in the service " + getInterface().getName() 
                + ". Tried " + len + " times of the providers " + providers 
                + " (" + providers.size() + "/" + copyinvokers.size() 
                + ") from the registry " + directory.getUrl().getAddress()
                + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version "
                + Version.getVersion() + ". Last error is: "
                + (le != null ? le.getMessage() : ""), le != null && le.getCause() != null ? le.getCause() : le);
    }

   這個方法就是遠程調用中會執行的Invoke鏈中的一個,經過:spa

        int len = getUrl().getMethodParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1;
        if (len <= 0) {
            len = 1;
        }

  上面這個判斷能夠猜到,文檔中說的值爲0關閉重試就是說的這句判斷了。上一句中對反射獲得的值進行了+1,這個+1就是加上了自己調用的一次,這裏就是最大可能執行的總次數。文檔中給出了一個方便人理解的值0來控制是否重試。因爲一些緣由只能用註解的方式,又沒法使用0,這裏的判斷是<=0,那咱們就在註解上設置-1或者更小均可以,因而結果就能夠知足須要了。通過測試發現確實能夠,因而問題解決的。注意,雖然問題解決了,但這個方式很是很差,只是限於一些緣由只能暫時採用這種彆扭的方式去作了,並不提倡。3d

==========================================================code

咱最近用的github:https://github.com/saaavsaaa

微信公衆號:

                      

相關文章
相關標籤/搜索