我们现在已经成功搭建服务注册中心、分布式配置中心,以及网关服务。但是我们只是简单的把分布式配置中心以及网关服务注册到服务注册中心,然后简单的从分布式配置中心读取配置,并没有真正体会到他们各自的特性。今天我们就以网关拦截器为例,通过定义黑白路径体验网关服务的拦截器功能以及分布式配置中心的自动刷新功能。
1. 路径拦截配置类
我们准备把黑白路径做成可配置的,这样一来,后续若有需求变更,直接改配置即可。其中@Data
注解时lombok
依赖的,用于声明这是一个实体类,将自动为成员变量allowPaths
和forbidPaths
生成getter
和setter
方法;@RefreshScope
用来指定配置刷新范围,自动刷新时会扫描到该类。
@Data
@RefreshScope
@ConfigurationProperties(prefix = "leyou.gateway.filter")
public class FilterProperties {
/**
* 允许访问,直接通过的请求路径
*/
private List<String> allowPaths;
/**
* 禁止访问请求路径
*/
private List<String> forbidPaths;
}
2. 路径拦截器
@Slf4j
@Component
public class PathFilter extends ZuulFilter {
@Autowired
private FilterProperties filterProperties;
/**
* 过滤器类型,包括以下4种类型:<p>
* 1、pre:请求在被路由之前执行。<br>
* 2、route:在路由请求时执行。<br>
* 3、post:在route和error过滤器之后执行。<br>
* 4、error:处理请求时发生错误执行。
*
* @return
*/
@Override
public String filterType() {
return "pre";
}
/**
* 定义过滤器的执行顺序,数字越小优先级越高。
*
* @return
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 判断该过滤器是否需要执行。返回true执行,返回false不执行。
*
* @return
*/
@Override
public boolean shouldFilter() {
// 1、获取请求上下文
RequestContext requestContext = RequestContext.getCurrentContext();
// 2、获取request对象
HttpServletRequest request = requestContext.getRequest();
// 3、获取请求路径
String requestURI = request.getRequestURI();
// 4、判断白名单
for (String allowPath : filterProperties.getAllowPaths()) {
if (requestURI.startsWith(allowPath)) {
return false;
}
}
return true;
}
/**
* 过滤器的具体业务逻辑
*
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
// 1、获取请求上下文
RequestContext requestContext = RequestContext.getCurrentContext();
// 2、获取request对象
HttpServletRequest request = requestContext.getRequest();
// 3、获取请求路径
String requestURI = request.getRequestURI();
// 4、判断黑名单
for (String forbidPath : filterProperties.getForbidPaths()) {
if (requestURI.startsWith(forbidPath)) {
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(403);
log.error("非法访问,地址:{}", request.getRemoteHost());
break;
}
}
return null;
}
}
3. 测试类
定义一个leyou.gateway.configValue
属性配置,默认值为Hi,在后面的例子,我们就将修改该值,然后看分布式配置中心是否能自动将属性值刷新。
@RefreshScope
@RestController
@RequestMapping("/gateway")
public class GatewayTestController {
@Value("${leyou.gateway.configValue:Hi}")
private String configValue;
@GetMapping("/allowPath")
public String allowPathsTest() {
return configValue + ",see you again.";
}
@GetMapping("/forbidPath")
public void forbidPathsTest() {
// do nothing
}
}
上面路径拦截配置类、路径拦截器以及测试类,我们都在网关服务写完了。但是要测试黑白路径以及配置自动刷新,我们还需要引入相关依赖、添加些配置才可以。
4. 引入依赖
在分布式配置中心和网关服务的模块pom.xml添加如下依赖:
<!--实现配置自动刷新-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-bus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
在网关服务再添加如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
5. 添加配置
5.1 分布式配置中心配置
server:
port: 9015
spring:
application:
name: ly-env-config-server
cloud:
config:
server:
git:
uri: https://gitee.com/anbang713/config-center.git # 指向git仓库地址,如果是私有仓库,则需要配置用户名和密码
search-paths: leyou # 指定服务配置所在的目录
bus:
trace:
enabled: true
enabled: true
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
eureka:
client:
service-url:
defaultZone: http://Anbang713:pwd713@localhost:9010/eureka/
instance:
lease-renewal-interval-in-seconds: 5 # 5秒钟发送一次心跳
lease-expiration-duration-in-seconds: 10 # 10秒不发送就过期
management:
endpoints:
web:
exposure:
include: bus-refresh
5.2 网关服务配置
eureka:
client:
service-url:
defaultZone: http://Anbang713:pwd713@localhost:9010/eureka/
instance:
lease-expiration-duration-in-seconds: 10
lease-renewal-interval-in-seconds: 5
leyou:
gateway:
configValue: Hello
filter:
allowPaths:
- /api/gateway/allowPath
forbidPaths:
- /api/gateway/forbidPath
server:
port: 9020
spring:
application:
name: ly-env-gateway-server
cloud:
bus:
enabled: true
trace:
enabled: true
rabbitmq:
host: localhost
password: guest
port: 5672
username: guest
virtual-host: /
zuul:
prefix: /api
routes:
ly-env-gateway-server:
path: /gateway/** # 以/api/gateway/**开头的请求,全部由网关服务处理
strip-prefix: false # 不截断/gateway
6. 测试
现在是这样的,我们在网关服务配置了/api/gateway/allowPath
为允许正常访问的路径,而/api/gateway/forbidPath
是不允许访问的路径,将被拦截器PathFilter
直接拦截。然后我们通过修改配置configValue
的值,在不重启服务的情况下看下日志输出值是否已经更新。
(1)启动服务,可以看到分布式配置中心和网关服务已成功注册到服务注册中心。
(2)访问http://localhost:9020/api/gateway/forbidPath
,访问被拒绝。
(3)访问http://localhost:9020/api/gateway/allowPath
,访问成功,并读取到分布式配置中心的属性值。
(4)更改分布式配置中心的属性值,我们将原来的hello
值修改成hello123
。
leyou:
gateway:
filter:
allowPaths:
- /api/gateway/allowPath
forbidPaths:
- /api/gateway/forbidPath
configValue: Hello123
(5)是否现在再直接访问http://localhost:9020/api/gateway/allowPath
就能获取到更改后的值呢?答案是不行的。
(6)那要怎样才能自动更新值呢?还记得我们引入的依赖吗?在分布式配置中心和网关服务我们都引入了spring-cloud-bus
和spring-cloud-stream-binder-rabbit
的依赖,以及在网关服务引入了spring-boot-starter-actuator
依赖。同时在分布式配置中心开放了bus-refresh
端点。其实仔细的朋友可以在分布式服务启动时输出了这样的日志信息:
2019-12-23 21:50:19.747 INFO 4036 --- [ main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/bus-refresh],methods=[POST]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
以及服务启动成功后,rabbitmq自动创建了名称为springCloudBus
类型为topic
的交换器和以springCloudBus.anonymous.**
开头的队列,并且它们的绑定队列是这样的。
好了,那我们大概知道配置自动刷新的策略是怎样的。其流程大致为:
- 刷新消息总线。
- 消息总线发送一条MQ消息。
- 监听MQ队列的消费者消费消息完成配置更新。
按照上述的流程,我们先刷新消息总线,响应成功。
同时,MQ也确实接收到了消息。
此时再访问http://localhost:9020/api/gateway/allowPath
可以看到,值已经更新到最新了。
到了这里,我只想说:好极了。在这之前,我们修改配置值,还要重启服务才能生效。但是现在,一切都变得如此美妙。
来源:CSDN
作者:Anbang713
链接:https://blog.csdn.net/Anbang713/article/details/103862818