天天看點

@notnull group如何使用_使用Http請求dubbo

問題

最近在學習SpringCloud , 以及将要在公司内部部署和推廣的過程中,發現網關既需要支援

http

,同時也需要支援

dubbo

,并且網關隻需要支援http即可,那麼在網關的内部就需要将http協定轉換成dubbo協定,在内部做又有2個處理方式

  • 1、在網關層面處理
    • 優點
      • 直接利用dubbo的泛化功能
      • 服務提供者不需要進行額外的處理
    • 缺點
      • 在網關層需要進行dubbo的tcp連接配接,如果業務的網絡環境比較特殊,那麼這一套是較難維護的
      • 接口的互動較為複雜,泛化需要将參數類型,參數等等進行傳遞,而這些服務提供者本身其實是存在的。
    • 2、在dubbo#provider層面進行處理
      • 優點
        • 直接對接http協定,不必處理額外的網絡環境
        • 僅需要傳遞dubbo服務需要的參數,不必傳遞額外的參數類型
      • 缺點
        • 如何讓服務提供者支援http轉dubbo.

通過上述的比較,以及公司業務上處理,我們選擇了第二種進行處理.

開發

一開始我們的服務是通過tomcat或者内置容器的SpringBoot進行暴露的,如果通路dubbo的話,過程就是

http --> nginx ---> tomcat ---> springmvc ---> dubbo

這個過程,而現在我們需要做的就是将這個過程中的SpringMVC這一塊進行移除,變成

http --> nginx ---> tomcat ---> dubbo

,進而直接支援http被dubbo處理。于是我通過SpringMVC的處理機制将Controller這一塊移除掉,達到了我們的目的,接下來看如何一步一步實作的.

假設url =

/dubbo/*

  • 通過包裝Servlet統一處理對接的http。
<servlet>
        <servlet-name>GatewayServlet</servlet-name>
        <servlet-class>com.xxx.gateway.dubbo.web.GatewayServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>GatewayServlet</servlet-name>
        <url-pattern>/dubbo/*</url-pattern>
    </servlet-mapping>
           
  • 通過http參數擷取dubbo服務的接口,版本等等資訊
String inf = servletRequest.getParameter("serviceName");
     Assert.notNull(inf, "接口不能為空!");
     String method = servletRequest.getParameter("method");
     Assert.notNull(method, "方法不能為空!");
     String uGroup = servletRequest.getParameter("group");
     String vVersion = servletRequest.getParameter("version");
     Assert.notNull(vVersion, "版本不能為空!");
           
  • 擷取dubbo服務
String[] beanNamesForType = this.applicationContext.getBeanNamesForType(ServiceConfig.class);
    Object ref = null;
    for (String service : beanNamesForType) {
        ServiceConfig serviceConfig = (ServiceConfig) this.applicationContext.getBean(service);
        String version = serviceConfig.getVersion();
        String anInterface = serviceConfig.getInterface();
        String group = serviceConfig.getGroup();
        if (!inf.equalsIgnoreCase(anInterface)) {
            continue;
        }
        if (!vVersion.equalsIgnoreCase(version)) {
            continue;
        }
        if (uGroup != null && !group.equalsIgnoreCase(uGroup)) {
            continue;
        }
        ref = serviceConfig.getRef();
        break;
    }
           
  • 利用SpringMVC的的處理機制将Controller移除
try {
            HttpServletRequest req = (HttpServletRequest) servletRequest;
            HttpServletResponse resp = (HttpServletResponse) servletResponse;
            ServletInvocableHandlerMethod invocableMethod = new ServletInvocableHandlerMethod(handlerMethod);
            WebDataBinderFactory binderFactory = getDataBinderFactory(invocableMethod);

            invocableMethod.setDataBinderFactory(binderFactory);
            ServletWebRequest webRequest = new ServletWebRequest(req, resp);
            ModelAndViewContainer mavContainer = new ModelAndViewContainer();

            HandlerMethodArgumentResolverComposite handlerMethodArgumentResolverComposite = new HandlerMethodArgumentResolverComposite();
            handlerMethodArgumentResolverComposite.addResolvers(getDefaultArgumentResolvers());
            invocableMethod.setHandlerMethodArgumentResolvers(handlerMethodArgumentResolverComposite);

            List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
            HandlerMethodReturnValueHandlerComposite returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
            invocableMethod.setHandlerMethodReturnValueHandlers(returnValueHandlers);

            invocableMethod.invokeAndHandle(webRequest, mavContainer);
            methodMap.put(handlerMethod, invocableMethod);
        } catch (Exception e) {
            fail(servletResponse, e);
        }
           
  • 如何突破傳遞參數的問題。 利用SpringMVC的

    HandlerMethodArgumentResolver

    即可解析

    到這一步,http轉dubbo就處理好了,測試發現SpringMVC在3,4,5的幾個大版本中稍有變動,相容花費一點時間。後續跟新會上傳的github。 :)

結論

Spring很強大.