在上一篇文章博主已经讲解了项目如何创建,不会的话可以前往学习,传送门:Spring Cloud Hoxton 版本微服务项目搭建eureka注册中心 以及 Spring Cloud Hoxton 版本微服务项目搭建 admin 监控管理中心 以及 Spring Cloud Hoxton 版本微服务项目搭建 config 配置中心客户端。
本篇用来讲解–Spring Cloud Hoxton 版本 gateway网关路由!
Spring Cloud Gateway 为 SpringBoot 应用提供了API网关支持,具有强大的智能路由与过滤器功能,本文将对其用法进行详细介绍。
SpringCloudGateway是SpringCloud新推出的网关框架,比较于上一代Zuul,功能和性能有很大的提升。Zuul1.x采用的是阻塞多线程方式,也就是一个线程处理一个连接请求,高并发情况下性能较差,即使是Zuul2.x虽然做到了非阻塞,但是面对连续跳票,看起来Zuul要被抛弃了。取而代之的是SpringCloudGateway,SpringCloudGateway是基于Webflux,是一个非阻塞异步的框架,性能上有很大提升,而且包含了Zuul的所有功能,可以从Zuul无缝切换到SpringCloudGateway
Gateway是在Spring生态系统之上构建的API网关服务,基于Spring 5,Spring Boot 2和 Project Reactor等技术。Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能, 例如:熔断、限流、重试等。
Spring Cloud Gateway 具有如下特性:
这里我们创建一个 gateway-center 模块来演示Gateway的常用功能。
在pom.xml中添加相关依赖(引入SpringCloudGateway需要的POM,记得引入actuator组件,否则服务发现中心会认为服务不在线,导致网关无法路由到服务,并且加入熔断组件Hystrix)
org.springframework.cloud
spring-cloud-starter-gateway
这里是我用到的依赖
4.0.0
com.cyj
Family
1.0-SNAPSHOT
com.cyj
gateway-center
0.0.1-SNAPSHOT
jar
gateway-center
CYJ:Spring Cloud GateWay 网关路由服务中心
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-starter-gateway
org.springframework.boot
spring-boot-starter-webflux
org.springframework.boot
spring-boot-starter-data-redis-reactive
org.springframework.cloud
spring-cloud-starter-oauth2
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-maven-plugin
gateway-center
spring-milestones
Spring Milestones
https://repo.spring.io/milestone
false
启动类如下:
package com.cyj.gatewaycenter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* 启动类
*
* @author Chenyongjia
* @Description: GatewayCenterApplication
* @ClassName: Application.java
* @Date 2020年01月02日 晚上20:29:06
* @Email [email protected]
*/
@Slf4j
@EnableEurekaClient
@SpringBootApplication
public class GatewayCenterApplication {
public static void main(String[] args) {
log.info("=======》启动 gateway-center 网关路由项目ing......");
SpringApplication.run(GatewayCenterApplication.class, args);
log.info("=======》启动 gateway-center 网关路由项目ing......");
}
}
两种不同的配置路由方式
Gateway 提供了两种不同的方式用于配置路由,一种是通过yml文件来配置,另一种是通过Java Bean来配置,这里就介绍yml的配置。
spring:
application:
#服务名称,随便写
name: gateway-center
cloud:
gateway:
discovery:
locator:
#开启从注册中心动态创建路由的功能
enabled: true
#使用小写服务名,默认是大写
lower-case-service-id: true
routes:
# 路由的ID
- id: path_route
# uri 代表路由的目标地址。注意:uri地址后面不要加 " / "
# 消息必须使用http进行转发,lb代表从注册中心获取服务
uri: lb://gateway-center # 可以直接跳转到具体的地址,如果要跳转到其他服务,则填写lb://<服务id>
predicates:
- Path=/gateway/** # 路由规则
filters:
- StripPrefix=1 # 不填则无法路由到其他服务
- AddRequestHeader=X-Request-Foo, Bar
- name: Hystrix # 添加熔断
args:
name: fallbackcmd
fallbackUri: forward:/fallback # 熔断跳转地址
完整配置如下:
eureka:
instance:
# 每隔5s发送一次心跳
lease-renewal-interval-in-seconds: 5
# 告知服务端10秒还未收到心跳的话,就将该服务移除列表
lease-expiration-duration-in-seconds: 10
# 健康检查路径
health-check-url-path: /actuator/health
client:
registry-fetch-interval-seconds: 5 # 默认为30秒
serviceUrl:
#eureka注册中心地址
defaultZone: http://localhost:8888/eureka/
#defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/,http://localhost:8890/eureka/
# Admin 管理配置
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always
server:
#项目端口号
port: 5010
tomcat:
max-connections: 200
max-threads: 300
min-spare-threads: 0
uri-encoding: UTF-8
spring:
application:
#服务名称,随便写
name: gateway-center
cloud:
gateway:
discovery:
locator:
#开启从注册中心动态创建路由的功能
enabled: true
#使用小写服务名,默认是大写
lower-case-service-id: true
routes:
# 路由的ID
- id: path_route
# uri 代表路由的目标地址。注意:uri地址后面不要加 " / "
# 消息必须使用http进行转发,lb代表从注册中心获取服务
uri: lb://gateway-center # 可以直接跳转到具体的地址,如果要跳转到其他服务,则填写lb://<服务id>
predicates:
- Path=/gateway/** # 路由规则
filters:
- StripPrefix=1 # 不填则无法路由到其他服务
- AddRequestHeader=X-Request-Foo, Bar
- name: Hystrix # 添加熔断
args:
name: fallbackcmd
fallbackUri: forward:/fallback # 熔断跳转地址
hystrix:
metrics:
enabled: true
polling-interval-ms: 3000
logging:
pattern:
console: "%d - %msg%n"
#path: D:\Logback-Test\ #日志输出到指定文件夹下默认名为spring.log
file: D:\Logback-Test\wordimg.log #日志输出到指定文件
#level: debug #指定级别
level: #指定输出某个类的日志
com.cnooc.wordimg.LoggerTest2: debug
#security:
# oauth2:
# resource:
# ####从认证授权中心上验证token
# tokenInfoUri: http://localhost:3010/serve-oauth/oauth/check_token
# preferTokenInfo: true
# client:
# accessTokenUri: http://localhost:3010/serve-oauth/oauth/token
# userAuthorizationUri: http://localhost:3010/serve-oauth/oauth/authorize
# clientId: client_1
# clientSecret: 123456
上面我们配置了熔断的配置,一旦发生熔断就会跳转到/fallback这个地址,下面我们实现一下这个接口,这里简单的返回了error,我们可以自定义处理熔断的逻辑,并且编写一个HTTP接口,来测试网关的调用,为了检测熔断的效果,这里通过参数来控制接口的响应时间
package com.cyj.gatewaycenter.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
/**
* @Description: 测试路由--控制器
* @BelongsProject: Family
* @BelongsPackage: com.cyj.gatewaycenter.controller
* @Author: ChenYongJia
* @CreateTime: 2020-01-02 15:52
* @Email: [email protected]
* @Version: 1.0
*/
@RestController
public class TestController {
@Value("${server.port}")
private String port;
/**
* 测试调用请求
* @param time
* @return
*/
@RequestMapping(value = "/get/{time}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity get(@PathVariable("time") long time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new ResponseEntity<>(port + " get ok.", HttpStatus.OK);
}
/**
* 发生熔断调用的请求
* @return
*/
@RequestMapping(value = "/fallback", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity fallback() {
return new ResponseEntity<>("error.", HttpStatus.OK);
}
}
网关配置好后,再启动一个其他的服务模块,记得添加引入actuator,否则无法被路由到,前面已经提到了我再提一次哈哈哈哈。
在同一注册中心下启动网关和服务,根据我们配置的路由规则 /gateway/**
,我们可以这样调用
http://localhost:5010/gateway/get/1
我们将响应时间改成5秒 http://localhost:5010/gateway/get/5000,超高熔断的检测时间,可以发现接口熔断,并且跳转到了指定的链接
spring:
application:
#服务名称,随便写
name: gateway-center
cloud:
gateway:
discovery:
locator:
#开启从注册中心动态创建路由的功能
enabled: true
#使用小写服务名,默认是大写
lower-case-service-id: true
routes:
# 路由的ID
- id: path_route
# uri 代表路由的目标地址。注意:uri地址后面不要加 " / "
# 消息必须使用http进行转发,lb代表从注册中心获取服务
uri: lb://gateway-center # 可以直接跳转到具体的地址,如果要跳转到其他服务,则填写lb://<服务id>
predicates: # 加入断言
- Path=/gateway/** # 路由规则
public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory {
public PreGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
exchange.getAttributes().put("requestTime", System.currentTimeMillis());
return chain.filter(exchange);
};
}
public static class Config {
}
}
(2)后置过滤器工厂,获取attribute里面的开始时间,并用当前时间减去,得到耗时时间,打印
public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory
{
public PostGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
Long startTime = exchange.getAttribute("requestTime");
long time = System.currentTimeMillis() - startTime;
System.out.println("接口耗时时间(ms):"+time);
}));
};
}
public static class Config {
}
}
(3)接下来将两个过滤器注入到Spring里面
@Configuration
public class FilterConfig
{
@Bean
public PreGatewayFilterFactory preGatewayFilterFactory() {
return new PreGatewayFilterFactory();
}
@Bean
public PostGatewayFilterFactory postGatewayFilterFactory() {
return new PostGatewayFilterFactory();
}
}
(4)前往application.yml进行过滤器的配置,在filter属性下配置上我们的自定义过滤器,根据框架的约定引用过滤器:比如我们的过滤器名称是PreGatewayFilterFactory,那我们引用的名称就是去掉GatewayFilterFactory这个后缀,也就是Pre,具体配置如下
spring:
application:
#服务名称,随便写
name: gateway-center
cloud:
gateway:
discovery:
locator:
#开启从注册中心动态创建路由的功能
enabled: true
#使用小写服务名,默认是大写
lower-case-service-id: true
routes:
# 路由的ID
- id: path_route
# uri 代表路由的目标地址。注意:uri地址后面不要加 " / "
# 消息必须使用http进行转发,lb代表从注册中心获取服务
uri: lb://gateway-center # 可以直接跳转到具体的地址,如果要跳转到其他服务,则填写lb://<服务id>
predicates:
- Path=/gateway/** # 路由规则
filters:
- StripPrefix=1 # 不填则无法路由到其他服务
- Pre # 自定义过滤器
- Post # 自定义过滤器
(5)接下来我们调用接口,可以看到耗时时间打在公屏上
其更多操作自己尝试一下!下一篇讲解gateway网关路由的限流。
更多参考精彩博文请看这里:《陈永佳的博客》
喜欢博主的小伙伴可以加个关注、点个赞哦,持续更新嘿嘿!