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);
} - 服务 id, 能够和 dubbo 一般调用的配置属性关联.
参数注意事项:
@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: 20861
server:
port: 8861
spring:
cloud:
nacos:
discovery:
namespace: dev
server-addr: 127.0.0.1:8848
整合 spring cloud gateway 网关配置:
dubbo:
cloud:
subscribed-services: dubbo-gateway-sample-provider
server:
port: 8862
spring:
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-provider
server:
port: 8862
spring:
cloud:
nacos:
discovery:
namespace: dev
server-addr: 127.0.0.1:8848
main:
allow-bean-definition-overriding: true
zuul:
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 版本