dubbo-gateway

dubbo-gateway 高性能dubbo网关,提供了http协定到dubbo协定的转换,但【并非】应用dubbo的【泛化】调用(泛化调用性能比一般调用有10-20%的损耗,通过一般异步的调用形式与基于webflux系列的响应式网关(spring cloud gateway)整合进步零碎的吞吐量,一般调用须要依赖api jar包,须要对接口定义进行革新,除此之外不须要做任何其它革新.另外也反对基于servlet类的利用或网关(spring cloud zuul)进行整合

泛化毛病

  • 泛化过程数据流会通过了三次转换, 会产生大量的长期对象, 有很大的内存要求。应用反射形式对于旨在榨干服务器性能以获取高吞吐量的零碎来说, 难以达到性能最佳
  • 同时服务端也会对泛化申请多一重 Map <-> POJO 的来回转换的过程。整体上,与一般的Dubbo调用相比有10-20%的损耗
  • 泛化调用在网关或服务消费者阶段无奈校验参数类型的有效性,数据要到服务提供者反序列化时能力校验出参数类型的有效性

    开源地址

    https://github.com/smallbeant...

    相干注解

    @GateWayDubbo

    标识这个接口须要主动进行协定转换

    /**

    • 服务id,能够和dubbo一般调用的配置属性关联.
      */

    @AliasFor("id")
    String value() default "";

    /**

    • 服务id,能够和dubbo一般调用的配置属性关联.
    • 例如:

       com.atommiddleware.cloud.config.dubboRefer.<userService>.version=1.1.0 com.atommiddleware.cloud.config.dubboRefer.<userService>.group=userSystem 以上相当于会调用版本号为1.1.0并且groupw为userSystem的dubbo服务,与@DubboReference的参数对齐,具体反对哪些参数详见配置类DubboReferenceConfigProperties

      */

    @AliasFor("value")
    String id() default "";

    @PathMapping

    标记这个接口办法须要进行协定主动转换

    /**

    • 门路表达式
      */

    @AliasFor("path")
    String value() default "";

    /**

    • 门路表达式
      */

    @AliasFor("value")
    String path() default "";

    /**

    • 提交办法,GET或POST
      */

    RequestMethod requestMethod() default RequestMethod.POST;

    public enum RequestMethod {

      GET, POST

    }

    @FromBody

    示意参数对象来源于音讯体

    /**

    • 是否查看参数
      */

    @AliasFor(annotation = ParamAttribute.class)
    boolean required() default true;

    @FromHeader

    示意参数对象来源于音讯头

    /**

    • 音讯头名称
      */

    @AliasFor(annotation = ParamAttribute.class)
    String value() default "";

    /**

    • 音讯头名称
      */

    @AliasFor(annotation = ParamAttribute.class)
    String name() default "";

    /**

    • 是否查看参数
      */

    @AliasFor(annotation = ParamAttribute.class)
    boolean required() default true;

    @FromCookie

    示意参数对象来源于cookie

    /**

    • cookie名称
      */

    @AliasFor(annotation = ParamAttribute.class)
    String value() default "";

    /**

    • cookie名称
      */

    @AliasFor(annotation = ParamAttribute.class)
    String name() default "";

    /**

    • 是否查看参数
      */

    @AliasFor(annotation = ParamAttribute.class)
    boolean required() default true;

    @FromPath

    示意参数对象来源于path,反对path表达式

    /**

    • path占位符名称
      */

    @AliasFor(annotation = ParamAttribute.class)
    String value() default "";

    /**

    • path占位符名称
      */

    @AliasFor(annotation = ParamAttribute.class)
    String name() default "";

    /**

    • 是否查看参数
      */

    @AliasFor(annotation = ParamAttribute.class)
    boolean required() default true;

    @FromQueryParams

    示意参数来源于query局部

    /**

    • query名称
      */

    @AliasFor(annotation = ParamAttribute.class)
    String value() default "";

    /**

    • query名称
      */

    @AliasFor(annotation = ParamAttribute.class)
    String name() default "";

    /**

    • 是否查看参数
      */

    @AliasFor(annotation = ParamAttribute.class)
    boolean required() default true;

    @FromAttribute

    示意参数来源于attribute

    /**

    • attribute 名称
      */

    @AliasFor(annotation = ParamAttribute.class)
    String value() default "";

    /**

    • attribute 名称
      */

    @AliasFor(annotation = ParamAttribute.class)
    String name() default "";

    /**

    • 是否查看参数
      */

    @AliasFor(annotation = ParamAttribute.class)
    boolean required() default true;

    配置示例

    @GateWayDubbo("userService")
    public interface UserService {

    /**

    • hello world
    • @return hello
      */

    @PathMapping(value="/sample/helloWorld",requestMethod=RequestMethod.GET)
    Result helloWorld();
    /**

    • 参数为空post申请
    • @return 后果
      */

    @PathMapping(value="/sample/helloWorldPost",requestMethod=RequestMethod.POST)
    Result helloWorldPost();
    /**

    • 返回值为空
      */

    @PathMapping(value="/sample/helloVoid",requestMethod=RequestMethod.GET)
    void helloVoid();
    /**

    • 返回值为空 post申请
      */

    @PathMapping(value="/sample/helloVoidPost",requestMethod=RequestMethod.POST)
    void helloVoidPost();
    /**

    • 注册用户
    • @param user 用户信息
    • @return 注册后果
      */

    @PathMapping("/sample/registerUser")
    Result registerUser(@FromBody User user);
    /**

    • 对象数据源来自header,headerName=user,headerValue=json(UrlEncoder后的字符串)
    • @param user 用户信息
    • @return 后果
      */

    @PathMapping(value="/sample/registerUserFromHeader",requestMethod=RequestMethod.GET)
    Result registerUserFromHeader(@FromHeader("user") User user);
    /**

    • header中以key value形式传递对象参数,headerName=headerValue转换为beanPropertyName=beanPropertyValue
    • headerName 对应bean 的propertyName,headerValue对应bean的propertyValue
    • @param user 用戶信息
    • @return 后果
      */

    @PathMapping(value="/sample/registerUserFromHeaderMap",requestMethod=RequestMethod.GET)
    Result registerUserFromHeaderMap(@FromHeader(value="user",paramFormat =ParamFormat.MAP) User user);
    /**

    • 对象数据源来自cookie,cookieName=user,cookieValue=json(UrlEncoder后的字符串)
    • @param user 用户信息
    • @return 后果
      */

    @PathMapping(value="/sample/registerUserFromCookie",requestMethod=RequestMethod.GET)
    Result registerUserFromCookie(@FromCookie("user") User user);
    /**

    • cookie中以 key value 形式传递对象参数,cookieName=cookieValue转化为beanPropertyName=beanPropertyValue
    • cookieName 对应bean 的propertyName,cookieValue对应bean的propertyValue,不反对嵌套对象转换,嵌套对象或简单参数请用json
    • @param user 用戶信息
    • @return 后果
      */

    @PathMapping(value="/sample/registerUserFromCookieMap",requestMethod=RequestMethod.GET)
    Result registerUserFromCookieMap(@FromCookie(value="user",paramFormat = ParamFormat.MAP) User user);
    /**

    • 对象数据源来自path,{user}=json(UrlEncoder后的字符串)
    • @param user 用户信息
    • @return 后果
      */

    @PathMapping(value="/sample/registerUserFromPath/{user}",requestMethod=RequestMethod.GET)
    Result registerUserFromPath(@FromPath("user") User user);
    /**

    • path pattern对应bean的属性名称
    • @param user 用户信息
    • @return 后果
      */

    @PathMapping(value="/sample/registerUserFromPathMap/{userName}/{age}/{gender}",requestMethod=RequestMethod.GET)
    Result registerUserFromPathMap(@FromPath(value="user",paramFormat = ParamFormat.MAP) User user);

    /**

    • 对象参数来源于query json字符串,user=json(UrlEncoder后的字符串)
    • @param user 用户信息
    • @return 后果
      */

    @PathMapping(value="/sample/getUserInfoFromQueryParamsParamFormatJSON",requestMethod=RequestMethod.GET)
    Result getUserInfoFromQueryParamsParamFormatJSON(@FromQueryParams(value="user")User user);

    /**

    • 对象参数来源于query,以key,value形式传参,key对应bean propertyName,value对应propertyValue,嵌套对象或简单对象请应用JSON
    • @param user 用户
    • @return 后果
      */

    @PathMapping(value="/sample/getUserInfoFromQueryParamsParamFormatMap",requestMethod=RequestMethod.GET)
    Result getUserInfoFromQueryParamsParamFormatMap(@FromQueryParams(value="user",paramFormat = ParamFormat.MAP)User user);
    /**

    • 数据起源queryParam
    • @param userId 用户id
    • @return 勾销登记后果
      */

    @PathMapping(value="/sample/unRegisterUser",requestMethod=RequestMethod.GET)
    Result unRegisterUser(@FromQueryParams("userId")Long userId);
    /**

    • 数据起源path
    • @param userId 用戶id
    • @return 后果
      */

    @PathMapping(value="/sample/getUserInfo/{userId}/{gender}",requestMethod=RequestMethod.GET)
    Result getUserInfo(@FromPath("userId") Long userId,@FromPath("gender") Short gender);
    /**

    • 数据起源header 和cookie
    • @param userId 用户id
    • @param age 年龄
    • @return 返回查问后果
      */

    @PathMapping(value="/sample/getUserInfo/byHeaderAndCookie",requestMethod=RequestMethod.GET)
    Result getUserInfo(@FromHeader("userId")Long userId,@FromCookie("age")Integer age);

    /**

    • 全场景
    • @param userId 用户id
    • @param age 年龄
    • @param gender 性别
    • @param user 用户信息
    • @return 查问后果
      */

    @PathMapping("/sample/getUserUserInfoAll/{userId}")
    Result getUserUserInfoAll(@FromPath("userId") Long userId,@FromCookie("age")Integer age,@FromHeader("gender")Long gender,@FromBody User user);
    }

参数注意事项:

@PathMapping参数 requestMethod:用于限定拜访服务的办法,反对POST与GET,默认为POST

@FromCookie、@FromPath、@FromHeader、@FromQueryParams参数 paramFormat:

  • JSON形式 限定参数名称对应的值为json字符串,而后通过反序列化json字符串失去参数对象(如@FromHeader("user") httpHeader应该要有一个头名称为user并且值为【样例数据】的json字符串(UrlEncode)),此将入参看做一个整体json字符串,默认json形式
  • MAP形式 限定对象的propertyName与单个参数一一对应【例如@FromHeader(value="user",paramFormat =ParamFormat.MAP) httpHeader应该要有头名称为userName、password、age、gender、dt等与User对象属性对应的头信息,User将获取这些头信息最终组装成残缺对象】,此形式不反对简单嵌套对象,简单嵌套对象请应用json
  • 此外如果办法的参数类型自身为根本数据类型,将固定应用Map形式,具体差别能够通过导入postman的测试用例体验

样例数据

{"userName": "admin","password": "123456","age": 99,"gender": 1,"dt": 1644431796892,"workHistory": {"workDescriptions": ["中学","大学"]} }

应用步骤

第一步:依照示例革新api接口,接口须要引入dubbo-gateway-api jar包

      <dependency>        <groupId>com.atommiddleware</groupId>        <artifactId>dubbo-gateway-api</artifactId>        <version>1.0.9</version>    </dependency>

第二步:网关引入革新后的jar包,同时援用以下jar包

`    <dependency>        <groupId>com.atommiddleware</groupId>        <artifactId>dubbo-gateway-spring-boot-starter</artifactId>        <version>1.0.9</version>    </dependency>`

第三步:在启动类上增加要扫描的api包名@DubboGatewayScanner(basePackages = "需扫描的api包名")

第四步: 网关配置routes(->看【配置核心】阐明),如果只是独自的spring mvc则不须要配置了

第五步:没了...就是这么简略

我的项目阐明

  • dubbo-gateway-api 是外围的api,相干注解都是在此我的项目中定义
  • dubbo-gateway-core 外围实现,实现dubbo-gateway的相干逻辑都在此我的项目中
  • dubbo-gateway-spring-boot-autoconfigure dubbo-gateway的主动拆卸
  • dubbo-gateway-spring-boot-starter dubbo-gateway的starter
  • dubbo-gateway-sample-api 示例服务api定义在此我的项目中
  • dubbo-gateway-sample-provider 基于spring cloud的dubbo 服务提供者示例
  • dubbo-gateway-sample 基于webflux(spring cloud gateway)的接入dubbo-gateway示例
  • dubbo-gateway-sample-web-provider 基于sevlet类型的dubbo服务提供者示例
  • dubbo-gateway-sample-web-consumer 基于sevlet类型spring mvc的我的项目接入dubbo-gateway示例
  • dubbo-gateway-sample-zuul 基于spring cloud zuul 接入dubbo-gateway示例
  • dubboGateWay.postman_collection.json 是导出的一份postman自测用例

    配置核心

    依照dubbo的失常接入配置进行配置就好了,以下贴出例子应用的配置在nacos配置核心的配置,其中filters应用了Dubbo作为过滤器

服务提供者配置:

dubbo:  protocol:    name: dubbo    port: 20861server:  port: 8861spring:  cloud:    nacos:      discovery:        namespace: dev        server-addr: 127.0.0.1:8848

整合spring cloud gateway 网关配置:

dubbo:  cloud:    subscribed-services: dubbo-gateway-sample-providerserver:  port: 8862spring:  cloud:    nacos:      discovery:        namespace: dev        server-addr: 127.0.0.1:8848    gateway:      routes:      - id: myGateway        uri: dubbo://127.0.0.1:8862        predicates:        - Path=/**

整合spring cloud zuul网关配置:

dubbo:  cloud:    subscribed-services: dubbo-gateway-sample-providerserver:  port: 8862spring:  cloud:    nacos:      discovery:        namespace: dev        server-addr: 127.0.0.1:8848  main:    allow-bean-definition-overriding: truezuul:  routes:    dubboService:      stripPrefix: false      url: dubbo://127.0.0.1      path: /**

留神:配置中的"D(d)ubbo"子眼示意应用的是dubbo gateway相干性能去解决路由,如果不配置则不会失效.
其中配置中uri(l) 配置除了dubbo相干字眼,其它信息并无实际意义,只是为了合乎网关的配置标准要求,能够配成127.0.0.1等

整合spring mvc 配置:

com.atommiddleware.cloud.config.includUrlPatterns=/sample/*,/order/*com.atommiddleware.cloud.config.excludUrlPatterns=

includUrlPatterns参数用于配置须要进行协定转换的url,excludUrlPatterns用于排除个别url,这两个参数只对【非】网关整合无效(因与网关整合path匹配交给了网关的path参数进行匹配)

序列化

接口:com.atommiddleware.cloud.core.serialize
json序列化默认采纳的是jackson,如果须要定制能够自行定制实现

输入响应

spring cloud gateway类型接口:com.atommiddleware.cloud.core.annotation.ResponseReactiveResult

spring mvc 类型接口:com.atommiddleware.cloud.core.annotation.ResponseServletResult

spring cloud zuul类型接口:com.atommiddleware.cloud.core.annotation.ResponseZuulServletResult

默认实现增加了一些简略的头信息,如果须要定制实现能够自行实现接口

错误码表

  • 404 匹配的地址在dubbo未发现对应的服务
  • 415 不反对的Media Type,默认反对[application/json,application/x-www-form-urlencoded]
  • 500 外部服务器谬误,个别为调用的dubbo服务抛出了异样或其它
  • 405 办法不容许,默认只反对[post,get],并且要与@PathMapping的requestMethod参数匹配

其它阐明

基于webflux的网关与基于servlet类的web利用接入整合形式是一样的步骤,例子应用的nacos版本2.0.3,如果须要在cookie,header,url,传递简单参数【非java根本类型】,需先将参数转为json,而后应用UrlEncode进行编码,js中能够应用encodeURIComponent进行编码,默认只反对GET,POST形式接入,ContentType反对application/json,application/x-www-form-urlencoded,简单参数倡议应用application/json,或我的项目整体都应用application/json

版本阐明

举荐应用1.0.9版本