中文网站建设小组,金华建设网站,互联网创业项目概述,哪里有做网站公司的文章目录SpringCloudGateway起步消费端整合SpringCloudGateway静态路由配置内置扩展网关过滤内置网关过滤自定义过滤全局过滤器内置全局过滤器自定义全局过滤器ForwardRoutingFilterNetty全局路由响应式负载均衡代理GatewayMetricsFilter网关度量过滤器#xff08;服务监控服务监控动态路由配置及持久化SpringCloudGateway起步 SpringCloudGateway是一个微服务的组件所以如果要想去使用它就必须自己手工创建微服务的项目同时肯定要有专属的微服务的依赖库那么下面就直接开整。 1、【microcloud项目】创建一个新的子模块模块的名称定义为“gateway-9501
2、【microcloud项目】修改build.gradle配置文件为gateway-9501模块添加所需要的依赖库 网关最终实现的是一个微服务的访问代理操作那么既然要进行访问代理就需要知道明确的已经存在的微服务的信息所有微服务的信息都在Nacos 中进行了保存这样一来就需要引入发现服务; project(:gateway-9501) { // 网关模块dependencies {implementation(com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery) {exclude group: com.alibaba.nacos, module: nacos-client // 移除旧版本的Nacos依赖}implementation(libraries.nacos-client) // 引入与当前的Nacos匹配的依赖库implementation(org.springframework.cloud:spring-cloud-starter-gateway) // 网关依赖}
}3、【gateway-9501子模块】在“src/main/resources”源代码目录之中创建 application.yml配置文件配置网关应用的端口以及Nacos相关的配置项。
server:port: 9501 # 网关服务的端口
spring:application:name: microcloud.gateway # 网关名称cloud: # Cloud配置nacos: # Nacos注册中心配置discovery: # 发现服务server-addr: nacos-server:8848 # Nacos服务地址namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间IDgroup: MICROCLOUD_GROUP # 一般建议大写cluster-name: MuyanGateway # 配置集群名称gateway: # 网关配置discovery: # 服务发现locator: # 资源定位enabled: true # 通过服务发现查找其他的微服务
4、【gateway-9501子模块】既然已经成功的开发了网关那么随后就可以在项目之中进行程序启动类的定义。
package com.yootk.gateway;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;SpringBootApplication
EnableDiscoveryClient
public class StartGatewayApplication9501 { // 网关应用启动类public static void main(String[] args) {SpringApplication.run(StartGatewayApplication9501.class, args);}
}此时所使用的是网关代码的最基础的开发模型同时最终还是要落实到具体的网关服务代理上。
5、【Nacos 控制台】当前的网关应用启动之后会向Nacos注册中心里面进行微服务的注册所以这个时候打开Nacos控制台观察是否已经正确注册(PS:请顺道启动一下部门微服务); 如果可以在微服务的列表里面看见已经启动了两个微服务的信息则表示当前的网关配置成功。 6、【本地系统】为了便于网关微服务的调用建议添加一个新的主机名称修改hosts配置文件:
127.0.0.1 gateway-95017、【Postman工具】既然已经启动了网关同时也设置了网关的主机名称那么下面就可以通过网关代理的形式来访问部门微服务的应用。 当前的SpringCloudGateway网关一旦引入了项目之中就可以直接利用网关来实现微服务的调用处理从整个的实现机制来说是没有任何难度的但是对于微服务已经起到了一层最基本的管理模式。
消费端整合SpringCloudGateway
当前的项目开发过程之中已经引入了SpringCloudGateway网关但是这个网关一旦引入之后不仅仅是针对于部门微服务调用的改进实际上也包含有消费端的改进这个改进仅仅是修改远程业务接口。
1、【common-api子模块】修改IDeptService接口对象。
package com.yootk.service;import com.yootk.common.dto.DeptDTO;
import com.yootk.service.config.FeignConfig;
import com.yootk.service.fallback.DeptServiceFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;import java.util.List;
import java.util.Map;
FeignClient(value microcloud.gateway, // 使用网关的名称进行访问configuration FeignConfig.class,fallbackFactory DeptServiceFallbackFactory.class) // 部门降级配置
public interface IDeptService { // 业务接口/*** 根据部门的编号获取部门的完整信息* param id 要查询的部门编号* return 编号存在则以DTO对象的形式返回部门数据如果不存在返回null*/GetMapping(/dept.provider/provider/dept/get/{deptno}) // 远程REST接口public DeptDTO get(PathVariable(deptno) long id);/*** 增加部门对象* param dto 保存要增加部门的详细数据* return 增加成功返回true否则返回false*/PostMapping(/dept.provider/provider/dept/add)public boolean add(DeptDTO dto);/*** 列出所有的部门数据信息* return 全部数据的集合 如果没有任何的部门数据则集合为空size() 0*/GetMapping(/dept.provider/provider/dept/list)public ListDeptDTO list();/*** 进行部门的分页数据加载操作* param currentPage 当前所在页* param lineSize 每页加载的数据行数* param column 模糊查询的数据列* param keyword 模糊查询关键字* return 部门集合数据以及统计数据返回的数据项包括* 1、key allDepts、value List集合部门的全部数据对象* 2、key allRecorders、value 总记录数* 3、key allPages、value 页数。*/GetMapping(/dept.provider/provider/dept/split)public MapString, Object split(RequestParam(cp) int currentPage,RequestParam(ls) int lineSize,RequestParam(col) String column,RequestParam(kw) String keyword);
}所有的消费端将原始编写的部门微服务的具体地址更改为网关的服务名称随后再修改每一个具体业务方法对应的路径的地址(把具体微服务的名称添加上来)就可以实现消费端的调用操作了。
静态路由配置 现在所开发的“gateway-9501”子模块是一种基于默认方式实现的网关调用整个的操作里面会自动的Nacos进行配置服务的抓取而后只要匹配成功了路径就可以进行调用这种形式没有任何的理解难度而在实际的开发之中很多网关之中的路由是需要由开发者配置的。 网关的主要目的有两个: 第一个是保护服务资源、第二个进行资源隔离某些资源是不希望被开放的)可是当前的网关开发等于开放了全部的访问端口中间仅仅是来了一个转发的功能。 网关的静态路由的维护性是很差。 此时的配置表示当前的网关只能够访问部门微服务之中的两个具体的路径地址而未配置的地址将无法进行访问。
内置 下面主要是针对于路由谓词工厂实现类来进行使用分析这个部分主要是一个基本的应用所有的谓词工厂只要会用即可而这些配置都在application.yml 中完成的。 1、【gateway-9501子模块】定义网关在指定日期之后允许访问 可以考虑某一个网关只能够在2050年之后允许你进行访问而在这之前是不允许你进行访问的如果要想实现这样的限制那么首先要获取一个日期时间数据内容这个内容是有特定的组成要求的这个格式可以通过Java之中提供的工具类来生成。
package com.yootk.test;import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;public class CreateGatewayDatetime { // 创建一个日期时间数据public static void main(String[] args) {DateTimeFormatter formatter DateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss);ZoneId zoneId ZoneId.systemDefault(); // 获取默认的区域IDLocalDateTime localDateTime LocalDateTime.parse(2050-02-17 21:15:32, formatter);ZonedDateTime now ZonedDateTime.of(localDateTime, zoneId);System.out.println(now);}
}server:port: 9501 # 网关服务的端口
spring:application:name: microcloud.gateway # 网关名称cloud: # Cloud配置nacos: # Nacos注册中心配置discovery: # 发现服务server-addr: nacos-server:8848 # Nacos服务地址namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间IDgroup: MICROCLOUD_GROUP # 一般建议大写cluster-name: MuyanGateway # 配置集群名称gateway: # 网关配置discovery: # 服务发现locator: # 资源定位enabled: false # 取消默认路由配置默认值就是falseroutes: # 定义静态路由- id: dept # 路由标记uri: lb://dept.provider # 负载均衡调用predicates: # 路由谓词工厂- Path/** # 匹配全部的路径- After2050-02-17T21:15:3208:00[Asia/Shanghai] # 指定日期时间之后访问像一般进行产品预售的时候往往会使用xx时间段之后进行接口的开放就可以通过网关来进行配置的。
2、【gateway-9501子模块】在进行请求的时候是可以向服务端发送Cookie访问数据的现在要求在访问网关的时候也必须传入指定的Cookie数据而后才允许访问。
server:port: 9501 # 网关服务的端口
spring:application:name: microcloud.gateway # 网关名称cloud: # Cloud配置nacos: # Nacos注册中心配置discovery: # 发现服务server-addr: nacos-server:8848 # Nacos服务地址namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间IDgroup: MICROCLOUD_GROUP # 一般建议大写cluster-name: MuyanGateway # 配置集群名称gateway: # 网关配置discovery: # 服务发现locator: # 资源定位enabled: false # 取消默认路由配置默认值就是falseroutes: # 定义静态路由- id: dept # 路由标记uri: lb://dept.provider # 负载均衡调用predicates: # 路由谓词工厂- Path/** # 匹配全部的路径- Cookiemuyan-yootk-key, muyan\-\w通过这样的谓词工厂可以保证网关的微服务调用更加的安全具体的安全在SpringCloud之中也有具体的应用的。
3、【gateway-9501子模块】既然已经可以实现Cookie的处理配置了那么下面就可以考虑通过头信息的形式来进行安全的防护了例如:要求必须传入指定的头信息之后才允许进行网关的调用。
server:port: 9501 # 网关服务的端口
spring:application:name: microcloud.gateway # 网关名称cloud: # Cloud配置nacos: # Nacos注册中心配置discovery: # 发现服务server-addr: nacos-server:8848 # Nacos服务地址namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间IDgroup: MICROCLOUD_GROUP # 一般建议大写cluster-name: MuyanGateway # 配置集群名称gateway: # 网关配置discovery: # 服务发现locator: # 资源定位enabled: false # 取消默认路由配置默认值就是falseroutes: # 定义静态路由- id: dept # 路由标记uri: lb://dept.provider # 负载均衡调用predicates: # 路由谓词工厂- Path/** # 匹配全部的路径- HeaderX-Muyan-Request-Id, \d # 具有指定的头信息允许访问 4、【gateway-9501子模块】只允许特定的主机进行访问。
server:port: 9501 # 网关服务的端口
spring:application:name: microcloud.gateway # 网关名称cloud: # Cloud配置nacos: # Nacos注册中心配置discovery: # 发现服务server-addr: nacos-server:8848 # Nacos服务地址namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间IDgroup: MICROCLOUD_GROUP # 一般建议大写cluster-name: MuyanGateway # 配置集群名称gateway: # 网关配置discovery: # 服务发现locator: # 资源定位enabled: false # 取消默认路由配置默认值就是falseroutes: # 定义静态路由- id: dept # 路由标记uri: lb://dept.provider # 负载均衡调用predicates: # 路由谓词工厂- Path/** # 匹配全部的路径- Hostgateway-**,**.yootk.com # 特定主机访问- MethodGET # 只允许GET模式访问5、 【gateway-9501子模块】在每次进行服务调用的时候实际上可以通过URL重写的形式发送一些请求数据过去这种数据一般被称为Query数据所以可以进行Query的数据验证。
server:port: 9501 # 网关服务的端口
spring:application:name: microcloud.gateway # 网关名称cloud: # Cloud配置nacos: # Nacos注册中心配置discovery: # 发现服务server-addr: nacos-server:8848 # Nacos服务地址namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间IDgroup: MICROCLOUD_GROUP # 一般建议大写cluster-name: MuyanGateway # 配置集群名称gateway: # 网关配置discovery: # 服务发现locator: # 资源定位enabled: false # 取消默认路由配置默认值就是falseroutes: # 定义静态路由- id: dept # 路由标记uri: lb://dept.provider # 负载均衡调用predicates: # 路由谓词工厂- Path/** # 匹配全部的路径- Querymsg, yootk-\w # 参数名称以及匹配的数据内容程序访问路径:gateway-9501:9501/provider/dept/list?msgyootk-lixinghua
所有的路由谓词工厂可以通过断言的形式对用户的请求进行各种的判断处理有了这些判断处理对于网关的服务管理是非常有帮助的所以网关在整个的项目开发之中不仅仅是一个所谓的服务治理功能还可以对一些请求进行拦截以及徼服务的保护。
扩展 通过之前的分析已经可以清楚的掌握SpringCloudGateway之中所提供的路由谓词工厂的作用了但是除了这些内置的路由谓词工厂的实现子类之外实际上还需要进行一些功能上的扩充需要例如:有些用户只允许在每天的“08:0O、“12:00”、“16:00”.“20:00”、“24:0O”这五个时间点上进行微服务的调用这种谓词路由工厂就不存在了就必须由开发者自行创建。 内置路由谓词工厂的基本的继承结构: 【接口】RoutePredicateFactory . l【抽象类】AbstractRoutePredicateFactory . 推荐做法就是在项目之中通过继承AbstractRoutePredicateFactory 抽象类来实现自定义路由谓词工厂的开发是比较合适的毕竟相比较接口来讲抽象类会有部分的公共实现。 1、 【gateway-9501子模块】创建一个用于保存时间分段的配置类这个配置类可以实现application.yml 中的配置写入
package com.yootk.gateway.predicate.config;import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;public class TimeSubsectionConfig {private SetString section new LinkedHashSet(); // 按照顺序保存不重复的数据public void setSection(ListString section) {this.section.addAll(section);}public SetString getSection() {return section;}
}
2、 【gateway-9501子模块】创建自定义路由谓词工厂类
package com.yootk.gateway.predicate.factory;import com.yootk.gateway.predicate.config.TimeSubsectionConfig;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;Component
public class DefaultTimeSubsectionRoutePredicateFactoryextends AbstractRoutePredicateFactoryTimeSubsectionConfig {// 既然需要根据当前的时间进行判断所以这个时候就需要有一个时间的转换处理类private static final DateTimeFormatter FORMATTER DateTimeFormatter.ofPattern(HH:mm);public DefaultTimeSubsectionRoutePredicateFactory() {super(TimeSubsectionConfig.class); // 传递配置项}Overridepublic PredicateServerWebExchange apply(TimeSubsectionConfig config) {return serverWebExchange - {String now LocalTime.now().format(FORMATTER); // 获取当前的时和分return config.getSection().contains(now); // 存在判断};}Overridepublic ListString shortcutFieldOrder() { // 配置项// 按照“,”定义多个不同的配置项而后此时会自动进行数据的拆分return Collections.singletonList(section); // 配置项的名称定义}Overridepublic ShortcutType shortcutType() { // 明确的定义分割项return ShortcutType.GATHER_LIST;}
}3、【gateway-9501子模块】修改application.yml配置文件追加新的自定义路由谓词工厂名称
server:port: 9501 # 网关服务的端口
spring:application:name: microcloud.gateway # 网关名称cloud: # Cloud配置nacos: # Nacos注册中心配置discovery: # 发现服务server-addr: nacos-server:8848 # Nacos服务地址namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间IDgroup: MICROCLOUD_GROUP # 一般建议大写cluster-name: MuyanGateway # 配置集群名称gateway: # 网关配置discovery: # 服务发现locator: # 资源定位enabled: false # 取消默认路由配置默认值就是falseroutes: # 定义静态路由- id: dept # 路由标记uri: lb://dept.provider # 负载均衡调用predicates: # 路由谓词工厂- Path/** # 匹配全部的路径- DefaultTimeSubsection08:00,16:00,20:00,24:00网关过滤
内置网关过滤
过滤的处理指的是可以自动的完成某些的功能配置例如:可以对用户的权限进行检测或者是在请求上添加额外的数据信息在SpringCloudGateway组件里面提供有过滤的处理支持能力。
所有的请求客户端需要通过网关来进行微服务的调用在调用之前肯定要进行断言处理判断能否访问指定的接口资源或者是否有指定的头信息存在而在最终进行服务调用的时候还可以进行过滤处理可以自动的在用户请求上添加一些头信息或者是传递额外的数据内容。这样在过滤操作结构之中就存在有两个阶段: PRE阶段(请求转发之前)、POST阶段(请求响应之前)。
1、【gateway-9501子模块】如果要想观察过滤的作用下面可以使用一个内置的过滤器来为请求自动的添加一个头信息 以及 别的过滤操作
server:port: 9501 # 网关服务的端口
spring:application:name: microcloud.gateway # 网关名称cloud: # Cloud配置nacos: # Nacos注册中心配置discovery: # 发现服务server-addr: nacos-server:8848 # Nacos服务地址namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间IDgroup: MICROCLOUD_GROUP # 一般建议大写cluster-name: MuyanGateway # 配置集群名称gateway: # 网关配置discovery: # 服务发现locator: # 资源定位enabled: false # 取消默认路由配置默认值就是falseroutes: # 定义静态路由- id: dept # 路由标记uri: lb://dept.provider # 负载均衡调用predicates: # 路由谓词工厂- Path/** # 匹配全部的路径filters: # 配置过滤器- AddRequestHeaderRequest-Token-Muyan, www.yootk.com # 追加头信息- AddRequestParametermessage, edu.yootk.com # 添加参数- MapRequestHeaderRequest-Token-Yootk, Muyan-Yootk-Key # 头信息转换- RemoveRequestHeaderRequest-Token-1234 # 删除指定的头信息- RedirectTo302, https://www.yootk.com # 必须设置3xx的代码同时进行重定向这样每当请求传递到网关之后那么就可以直接添加一个头信息并且将头信息随着请求发送到目标微服务上。由于此时微服务端可以实现所有请求头信息的输出通过后台的日志可以清楚的发现内容已经存在了所以过滤可以帮助用户完善一些业务的处理同时具有自动的处理支持能力。
自定义过滤
在SpringCloudGateway之中只要按照既定的结构也是可以轻松的实现自定义过滤工厂的配置的那么下面首先通过基本的操作形式观察过滤工厂的具体定义结构。
1、【gateway-9501子模块】创建一个日志过滤工厂
package com.yootk.gateway.filter;import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;Slf4j
Component
public class LogGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {// 日志过滤工厂类Overridepublic GatewayFilter apply(NameValueConfig config) { // 过滤处理return (exchange, chain) - { // 编写具体的过滤实现ServerHttpRequest request exchange.getRequest().mutate().build();ServerWebExchange webExchange exchange.mutate().request(request).build();log.info(配置参数{}{}, config.getName(), config.getValue()); // application.ymllog.info(请求路径{}、请求模式{}, request.getPath(), request.getMethod());return chain.filter(webExchange); // 向下执行};}}2、 【gateway-9501子模块】所有的过滤器如果要想生效则必须在application.yml之中进行配置。
server:port: 9501 # 网关服务的端口
spring:application:name: microcloud.gateway # 网关名称cloud: # Cloud配置nacos: # Nacos注册中心配置discovery: # 发现服务server-addr: nacos-server:8848 # Nacos服务地址namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间IDgroup: MICROCLOUD_GROUP # 一般建议大写cluster-name: MuyanGateway # 配置集群名称gateway: # 网关配置discovery: # 服务发现locator: # 资源定位enabled: false # 取消默认路由配置默认值就是falseroutes: # 定义静态路由- id: dept # 路由标记uri: lb://dept.provider # 负载均衡调用predicates: # 路由谓词工厂- Path/** # 匹配全部的路径filters: # 配置过滤器- RemoveRequestHeaderRequest-Token-Muyan # 删除指定的头信息- Logmuyan, yootk # 过滤器NameValueConfigname属性, value属性那么此时就根据已有的过滤工厂结构实现了自定义的过滤器配置从而可以实现更加方便的开发过滤器是一个公共且可以自动完成的处理机制。
全局过滤器
在SpringCloudGateway里面所有的请求和响应的处理操作全部都需要经过一系列的过滤器来进行处理通过断言来确定该路由是否执行而后具体的执行过程之中就要使用到过滤器。 网关的主要作用是进行代理资源的请求转发而在SpringCloudGateway中为了实现这样的转发处理机制提供了一个GlobalFilter(全局过滤接口该接口的核心功能实现了一个请求转发的处理操作在进行请求转发处理之前需要执行一些过滤的处理操作(认证与授权操作);
网关的请求最终都是由GlobalFilter实现转发处理的所以开发者可以通过全局过滤器来实现统一的业务处理需求例如:认证与授权检测、服务限流等。
内置全局过滤器
SpringCloudGateway 之中比较强悍的一点在于里面有大量的内置过滤器的存在这些过滤器不管用户是否使用已经为用户安排好了但是如果要想获取到这些过滤器的信息那么就需要通过如下的步骤来完成(通过Actuator来获取)。 1、【microcloud项目】修改build.gradle配置文件为gateway-9501子模块添加所需要的依赖库:
project(:gateway-9501) { // 网关模块dependencies {implementation(com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery) {exclude group: com.alibaba.nacos, module: nacos-client // 移除旧版本的Nacos依赖}implementation(libraries.nacos-client) // 引入与当前的Nacos匹配的依赖库implementation(org.springframework.cloud:spring-cloud-starter-gateway) // 网关依赖implementation(org.springframework.boot:spring-boot-starter-actuator) // Actuator依赖库}
}2、 【gateway-9501子模块】如果要想启用Actuator监控还需要修改application.yml配置文件在这个配置文件之中启用全部的Actuator 监控终端
management:server:port: 9090 # Actuator端口endpoints:web:exposure:include: * # 开启全部的监控终端base-path: /actuator # 访问子路径3、【Postman测试】启动当前的网关应用模块随后通过 Postman进行接口调用测试得到全局过滤
gateway-9501:9090/actuator/gateway/globalfilters如果要想去研究这些过滤器那么首先需要解决的问题就是过滤器的实现类的继承结构所有的过滤器都会继承一个公共的父接口—— org.springframework.cloud.gateway.filter.GlobalFilter在这个接口里面提供有一个过滤的处理方法: 既然此时已经找到了父接口那么就可以依据这个父接口查看其所有可能存在的实现子类。
自定义全局过滤器
在网关之中的过滤器的开发本身是非常容易的因为只要有GlobalFilter 接口而后定义一个具体的实现子类并且将其配置到Spring容器之中那么就可以直接使用了本次创建一个复合全局过滤器。
1、【gateway-9501子模块】创建全局过滤器同时在该过滤器中配置有两个过滤的操作处理。
package com.yootk.gateway.filter.global;import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import reactor.core.publisher.Mono;Configuration // 向容器之中进行注册
Slf4j // 启用日志注解
public class CombinedGlobalFilter { // 自定义过滤器Bean // 进行Bean注册Order(-20) // 数值越小执行越靠前public GlobalFilter getFirstFilter() { // 创建一个过滤器return (exchange, chain) - {log.info(【FirstFilter - PRE阶段】请求ID{}、请求路径{},exchange.getRequest().getId(), exchange.getRequest().getPath());return chain.filter(exchange).then(Mono.fromRunnable(()-{log.info(【FirstFilter - POST阶段】请求ID{}、请求路径{},exchange.getRequest().getId(), exchange.getRequest().getPath());}));};// 创建过滤器的实例}Bean // 进行Bean注册Order(-10) // 数值越小执行越靠前public GlobalFilter getSecondFilter() { // 创建二个过滤器return (exchange, chain) - {log.info(【SecondFilter - PRE阶段】请求ID{}、请求路径{},exchange.getRequest().getId(), exchange.getRequest().getPath());return chain.filter(exchange).then(Mono.fromRunnable(()-{log.info(【SecondFilter - POST阶段】请求ID{}、请求路径{},exchange.getRequest().getId(), exchange.getRequest().getPath());}));};// 创建过滤器的实例}
}2、【Postman 工具】既然已经定义好了全局过滤器那么就需要通过Actuator监控来查看该过滤器是否存在。gateway-9501:9090/actuator/gateway/globalfilters
3、【Postman 工具】既然网关已经启用了过滤器那么随后就需要通过测试来观察此过滤器是否正常执行。 【FirstFilter - PRE阶段】请求ID:065eedeb-2、请求路径:/provider/dept/list 【SecondFilter - PRE阶段】请求ID:065eedeb-2、请求路径:/provider/dept/listFlippingproperty:dept.providerribbon.ActiveConnectionsLimittouseNEXTpropertyniws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit 2147483647 【SecondFilter - POST阶段】请求ID:065eedeb-2、请求路径:/provider/dept/lis 【FirstFilter - POST阶段】请求ID:065eedeb-2、请求路径:/provider/dept/list 此时的过滤器使用了Order配置了执行的顺序所以在执行的时候就会按照: ForwardRoutingFilter Forward就是一个转发的操作含义SpringCloudGateway网关是基于WebFlux 技术开发出来的这样除了可以实现其下游资源的转发之外也可以在网关的内部定义所需的服务接口此时就可以在网关中配置采用“forward://路径”的形式实现 如果在 application.yml里面配置了以“forward:/”开头的路径这个时候就会使用ForwardRoutingFilter进行处理由于此概念比较抽象下面还是基于以上的模型动手来实现一个该操作。
1、【gateway-9501子模块】在网关内部定义一个访问资源用于实现内部转换操作。
package com.yootk.gateway.action;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ServerWebExchange;import java.util.HashMap;
import java.util.Map;RestController
RequestMapping(/gateway/action/*) // 定义访问父路径
public class GatewayAction { // 网关ActionRequestMapping(globalforward) // 定义子路径public MapString, String forward(ServerWebExchange exchange) {MapString, String result new HashMap(); // 保存所有的处理结果result.put(message, forward); // 信息保存result.put(requestId, exchange.getRequest().getId());result.put(requestPath, exchange.getRequest().getPath().toString());return result;}
}
再次提醒的是此时定义的Action是在网关内部定义的一个路径该路径没有进行所谓的转发处理仅仅是在网关的内部实现了信息的显示
2、【gateway-9501子模块】修改application.yml配置文件配置一个本地转发路由
spring:application:name: microcloud.gateway # 网关名称cloud: # Cloud配置nacos: # Nacos注册中心配置discovery: # 发现服务server-addr: nacos-server:8848 # Nacos服务地址namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间IDgroup: MICROCLOUD_GROUP # 一般建议大写cluster-name: MuyanGateway # 配置集群名称gateway: # 网关配置discovery: # 服务发现locator: # 资源定位enabled: false # 取消默认路由配置默认值就是falseroutes: # 定义静态路由- id: forward_example # 配置路由IDuri: forward://globalforward # 配置本地转发predicates:- Path/globalforward # 配置访问路径filters:- PrefixPath/gateway/action # 路径前缀- id: dept # 路由标记uri: lb://dept.provider # 负载均衡调用predicates: # 路由谓词工厂- Path/** # 匹配全部的路径filters: # 配置过滤器- RemoveRequestHeaderRequest-Token-Muyan # 删除指定的头信息- Logmuyan, yootk # 过滤器NameValueConfigname属性, value属性3、【Postman工具】此时已经配置完成了全部的结构那么下面就可以通过Postman访问forward 配置的路径:
gateway-9501:9501/globalfoward此时的程序已经实现了内部的路径匹配这样直接访问forward配置的路径之后就可以跳转到内部实现但是这种操作是由专属的全局过滤器来完成的 SpringCloudGateway网关开发之中采用的是Reactive 开发模型实现的采用的是响应式的编程方式实现代码 Netty全局路由
SpringCloudGateway 网关技术除了可以实现微服务的代理之外实际上还可以访问各种外网的资源此时只需要设置到正确的服务地址即可。
1、【gateway-9501子模块】下面配置一个外网访问定义一个“/muyan-yootk”的断言地址而后让其跳转到沐言优拓的官方首页: ““https://www.yootk.com/resources”; 此时所给出的资源采用的是“https”开头修改application.yml配置文件
spring:application:name: microcloud.gateway # 网关名称cloud: # Cloud配置nacos: # Nacos注册中心配置discovery: # 发现服务server-addr: nacos-server:8848 # Nacos服务地址namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间IDgroup: MICROCLOUD_GROUP # 一般建议大写cluster-name: MuyanGateway # 配置集群名称gateway: # 网关配置discovery: # 服务发现locator: # 资源定位enabled: false # 取消默认路由配置默认值就是falseroutes: # 定义静态路由- id: yootk_example # 配置路由IDuri: https://www.yootk.com/resources # 设置访问路径的匹配predicates:- Path/muyan-yootk # 配置访问路径2、【Postman工具】重新启动路由应用随后通过Postman工具来进行访问路径: gateway-9501.9501/muyan-yootk额外说明: 对于现在很多的服务对接来讲使用RESTful设计架构的交互模式已经非常的多了那么在以后的开发过程之中会通过REST 实现各类服务的整合此时最佳的做法就是通过网关集成。 现在的问题就来了具体的整个处理是由那个过滤器完成的呢?于是可以告诉大家,是由Netty过滤器完成的。 可以发现在进行最终资源响应的时候还会通过NettyWriteResponseFilter来处理在NettyRoutingFilter之中所进行的响应仅仅是服务端数据的响应接收而不是最终响应给微服务客户端的数据而这个响应的数据需要NettyWriteResponseFilter过滤器来实现。 在使用SpringCloudGateway进行HTTP或HTTPS资源访问的时候所采用的是何种模式? 采用的是Netty开发模型完成的服务资源的处理。 响应式负载均衡代理 在微服务设计的时候集群是肯定要优先考虑到的问题包括在之前进行网关基本整合的时候也整合过多个微服务的节点在整合的过程里面将地址使用了“lb://服务ID”的形式进行注册随后就可以启动负载均衡处理了。 网关可以采用“lb://服务名称”的形式实现某一个微服务集群的转发代理操作同时在进行调用时还提供有负载均衡的支持(LoadBalancer)而在SpringCloudGateway中针对于负载均衡代理有两个GlobalFilter实现类: 1、默认的负载均衡代理类(LoadBalancerClientFilter) 2、响应式负载均衡代理类(ReactiveLoadBalancerClientFilter) 通过源代码可以发现LoadBalancerClientFilter 这个网关过滤器已经不再推荐使用了那么随后可以考虑通过Actuator给出的访问路径来观察当前的网关里面所支持的过滤器是否包含有当前的这个过滤器。 gateway-9501:9090/actuator/gateway/globalfilters 在当前的情况下默认所使用的负载均衡过滤器是一个不推荐继续使用的过滤器了因为这个过滤器实现过程之中采用的是一种同步的处理形式完成的这一点对于网关的性能是非常致命的所以应该考虑更换为ReactiveLoadBalancerClientFilter过滤器了 如何更换? 可以发现此时的程序类之中所使用的org.springframework.cloud.loadbalancer开发包是不存在的,所以当前这种基于响应式的负载均衡的过滤器肯定无法使用。解决的方案只有一个:引入新的依赖库。 1.【microcloud项目】如果要想使用响应式的负载均衡过滤器则需要引入一个新的依赖库修改build.gradle配置文件: project(:gateway-9501) { // 网关模块dependencies {implementation(com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery) {exclude group: com.alibaba.nacos, module: nacos-client // 移除旧版本的Nacos依赖}implementation(libraries.nacos-client) // 引入与当前的Nacos匹配的依赖库implementation(org.springframework.cloud:spring-cloud-starter-gateway) // 网关依赖implementation(org.springframework.boot:spring-boot-starter-actuator) // Actuator依赖库implementation(org.springframework.cloud:spring-cloud-starter-loadbalancer)}
}
2、【gateway-9501子模块】遗憾的是此时再次查询出来发现并没有进行过滤器的更换因为还需要修改application.yml配置文件关闭默认的负载均衡配置。
spring:application:name: microcloud.gateway # 网关名称cloud: # Cloud配置loadbalancer:ribbon:enabled: false # 关闭默认配置3、【Postman 工具】配置完成之后再次查看当前全部网关过滤器配置项可以发现已经启用了响应式的负载均衡处理。 4、【gateway-9501子模块】虽然此时已经成功的更换了负载均衡加载器但是随后又会出现有一个新的警告信息这个警告信息是在每次启动网关的时候出现的日志信息。 中文含义: SpringCloud负载均衡在当前所使用默认缓存是一个Caffeine缓存组件当前默认的缓存组件性能贼高命中率非常的高同时基于了LRU算法)是Guava后续版本延续 5、【microcloud项目】修改 build.gradle配置文件引入 Caffeine缓存组件依赖库:
dependencies.gradle
ext.versions [caffeine : 3.0.4, // Caffeine缓存组件版本号
]
ext.libraries [// 以下的配置为LoadBalancer所需要的Caffeine组件有关依赖caffeine : com.github.ben-manes.caffeine:caffeine:${versions.caffeine}
]build.gradle
project(:gateway-9501) { // 网关模块dependencies {implementation(com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery) {exclude group: com.alibaba.nacos, module: nacos-client // 移除旧版本的Nacos依赖}implementation(libraries.nacos-client) // 引入与当前的Nacos匹配的依赖库implementation(org.springframework.cloud:spring-cloud-starter-gateway) // 网关依赖implementation(org.springframework.boot:spring-boot-starter-actuator) // Actuator依赖库implementation(org.springframework.cloud:spring-cloud-starter-loadbalancer)implementation(libraries.caffeine)}
}一切都配置完成之后当前的网关在启动时候就没有了之前的警告信息同时对于网关的处理性能也有了很大的提高所以这个时候才是一个在实际的应用开发中所应该具有的网关的样子。
GatewayMetricsFilter网关度量过滤器服务监控
SpringCloudGateway是一个独立的应用, 而且这种应用全部都是基于SpringBoot基础之上开发出来的, 在学习SpringBoot之中讲解过了关于Actuator Prometheus Grafana 实现服务监控的操作案例那么本次可以直接利用已经搭建完成的监控服务器(Prometheus Grafana)实现网关监控数据的获取。
1、【microcloud项目】如果要想进行服务的监控数据采集(所有的数据被采集到Prometheus之中)那么就需要修改项目所对应的依赖库修改build.gradle配置文件:
dependencies.gradle
ext.versions [micrometer : 1.7.0, // Prometheus相关监控依赖与服务部署的版本号相同
]
ext.libraries [// 以下的配置为Prometheus服务整合micrometer-registry-prometheus: io.micrometer:micrometer-registry-prometheus:${versions.micrometer},micrometer-core: io.micrometer:micrometer-core:${versions.micrometer},
]build.gradle
project(:gateway-9501) { // 网关模块dependencies {implementation(com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery) {exclude group: com.alibaba.nacos, module: nacos-client // 移除旧版本的Nacos依赖}implementation(libraries.nacos-client) // 引入与当前的Nacos匹配的依赖库implementation(org.springframework.cloud:spring-cloud-starter-gateway) // 网关依赖implementation(org.springframework.boot:spring-boot-starter-actuator) // Actuator依赖库implementation(org.springframework.cloud:spring-cloud-starter-loadbalancer)implementation(libraries.caffeine)implementation(libraries.micrometer-registry-prometheus)implementation(libraries.micrometer-core)}
}
2、【gateway-9501子模块】修改application.yml配置文件启用metrics监控
spring:application:name: microcloud.gateway # 网关名称cloud: # Cloud配置loadbalancer:ribbon:enabled: false # 关闭默认配置nacos: # Nacos注册中心配置discovery: # 发现服务server-addr: nacos-server:8848 # Nacos服务地址namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间IDgroup: MICROCLOUD_GROUP # 一般建议大写cluster-name: MuyanGateway # 配置集群名称username: muyan # 用户名password: yootk # 密码gateway: # 网关配置metrics:enabled: true # 启用服务监控3、【Postman 工具】此时已经启用了网关的Actuator监控那么下面通过Postman查看一下监控数据: 4、【promethues-server】打开Prometheus配置文件:vi /usr/local/prometheus/prometheus.yml 5、【promethues-server】修改Prometheus配置文件添加网关的监控路径。
global:scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
scrape_configs:- job_name: microcloudscrape_interval: 10sscrape_timeout: 5smetrics_path: /actuator/prometheusstatic_configs:- targets: [gateway-server:9090]
6、【prometheus-server】检查当前的Prometheus配置是否正确:
/usr/local/prometheus/promtool check config /usr/local/prometheus/prometheus.yml7、【prometheus-server】启动当前的Prometheus服务进程: systemctl start prometheus 8、【prometheus-server】查看一下当前端口的占用情况配置的Prometheus占用的是999端口: netstat -nptl
9、【Prometheus控制台】由于在当前的系统之中已经配置了主机名称直接输入路径: http://prometheus-server:9999/ 10、【grafana-server】为了更加丰富图形展示的效果那么可以启用Grafana服务: systemctl start grafana; 11、【grafana控制台】本地系统已经配置了hosts主机名称所以直接打开控制台观察:
http://grafana-server:3000在之前所配置的账户信息为: admin / admin 只要是服务开发那么伴随的一定有两个隐含的内容: 认证与授权、服务监控与警报。
动态路由配置及持久化
虽然已经可以通过REST接口实现动态路由的配置了,但是这些配置一旦在网关重新启动之后所有的配置项依然会自动消失除非你个人可以在每次重新启动之后不厌其烦的进行路由的配置否则最佳的做法就是找到一个存储空间。
1、【Nacos控制台】在dev的命名空间下定义一个新的配置项配置项的名称为:Gateway.config
[{id: dept,uri: lb://dept.provider,order: 1,predicates: [{name: Path,args: {pattern: /**}}],filters: [{name: AddRequestHeader,args: {_genkey_0: Request-Token-Muyan,_genkey_1: www.yootk.com}}]}
]2、【microcloud项目】为“gateway-9501”添加相关的依赖库这个地方主要是配置Nacos 有关的依赖库。
project(:gateway-9501) { // 网关模块dependencies {implementation(com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery) {exclude group: com.alibaba.nacos, module: nacos-client // 移除旧版本的Nacos依赖}implementation(libraries.nacos-client) // 引入与当前的Nacos匹配的依赖库implementation(org.springframework.cloud:spring-cloud-starter-gateway) // 网关依赖implementation(org.springframework.boot:spring-boot-starter-actuator) // Actuator依赖库implementation(org.springframework.cloud:spring-cloud-starter-loadbalancer)implementation(libraries.caffeine)implementation(libraries.micrometer-registry-prometheus)implementation(libraries.micrometer-core)}
}3、【gateway-9501子模块】此时需要通过Gateway对Nacos做监听而这个监听跟已有的Nacos配置是两回事所以应该创建一个网关的Nacos配置存储类。
package com.yootk.gateway.config;import com.alibaba.nacos.api.PropertyKeyConst;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.Properties;Component
Data
ConfigurationProperties(prefix spring.cloud.nacos.discovery)
public class GatewayNacosConfig { // 自定义配置存储类private String serverAddr;private String namespace;private String group;private String dataId gateway.config;private long timeout 2000;public Properties getNacosProperties() {Properties properties new Properties();properties.put(PropertyKeyConst.SERVER_ADDR, this.serverAddr);properties.put(PropertyKeyConst.NAMESPACE, this.namespace);return properties;}
}4、【gateway-9501子模块】创建路由数据的操作业务类。
package com.yootk.gateway.service;import javassist.NotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;Service
Slf4j
public class DynamicRouteService implements ApplicationEventPublisherAware {Autowiredprivate RouteDefinitionWriter routeDefinitionWriter; // 路由数据的写入private ApplicationEventPublisher publisher; // 事件发布器Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.publisher applicationEventPublisher; // 保存事件发布器}public boolean add(RouteDefinition definition) { // 追加新的路由配置log.info(增加路由配置项新的路由ID为{}, definition.getId()); // 日志输出try {this.routeDefinitionWriter.save(Mono.just(definition)).subscribe(); // 配置写入this.publisher.publishEvent(new RefreshRoutesEvent(this)); // 发布路由事件} catch (Exception e) {e.printStackTrace();log.error(路由增加失败增加的路由ID为{}, definition.getId());return false;}return true;}public MonoResponseEntityObject delete(String id) { // 根据id删除数据log.info(删除路由配置项删除的路由ID为{}, id); // 日志输出return this.routeDefinitionWriter.delete(Mono.just(id)).then(Mono.defer(() - {return Mono.just(ResponseEntity.ok().build());})).onErrorResume((t) - {return t instanceof NotFoundException;}, (r) - {return Mono.just(ResponseEntity.notFound().build());});}public boolean update(RouteDefinition definition) { // 修改已有的路由配置log.info(更新路由配置项新的路由ID为{}, definition.getId()); // 日志输出try {this.delete(definition.getId()); // 根据ID删除已有路由this.routeDefinitionWriter.save(Mono.just(definition)).subscribe(); // 配置写入this.publisher.publishEvent(new RefreshRoutesEvent(this)); // 发布路由事件} catch (Exception e) {log.error(路由更新失败增加的路由ID为{}, definition.getId());return false;}return true;}
}5、【gateway-9501子模块】定义监听处理类此时的操作最好可以在容器启动之后运行。
package com.yootk.gateway.listener;import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yootk.gateway.config.GatewayNacosConfig;
import com.yootk.gateway.service.DynamicRouteService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.stereotype.Component;import java.util.concurrent.Executor;Component
Slf4j
public class GatewayNacosRouteListener implements CommandLineRunner {Autowiredprivate DynamicRouteService dynamicRouteService; // 设置业务层处理Autowiredprivate GatewayNacosConfig nacosConfig; // Nacos服务配置// 因为Nacos里面保存的数据类型是JSON数据所以需要对JSON进行解析直接使用Jackson组件了Autowiredprivate ObjectMapper mapper; // 获取Jackson组件Overridepublic void run(String... args) throws Exception {this.nacosDynmaicRouteListener();// 启动时加载配置}public void nacosDynmaicRouteListener() { // 动态路由监听try {ConfigService configService NacosFactory.createConfigService(this.nacosConfig.getNacosProperties());String content configService.getConfig(this.nacosConfig.getDataId(), this.nacosConfig.getGroup(), this.nacosConfig.getTimeout()); // 获取指定的配置项log.info(【网关启动】读取Nacos网关配置项{}, content); // 日志输出GatewayNacosRouteListener.this.setRoute(content); // 路由配置configService.addListener(this.nacosConfig.getDataId(), this.nacosConfig.getGroup(), new Listener() {Overridepublic Executor getExecutor() {return null;}Overridepublic void receiveConfigInfo(String configInfo) {log.info(【网关更新】读取Nacos网关配置项{}, configInfo); // 日志输出GatewayNacosRouteListener.this.setRoute(configInfo);}});} catch (Exception e) {e.printStackTrace();}}private void setRoute(String configInfo) { // 定义路由处理try { // 将读取到的数据内容转为路由的配置定义本操作是由Jackson组件完成的RouteDefinition[] routes this.mapper.readValue(configInfo, RouteDefinition[].class);for (RouteDefinition route : routes) {this.dynamicRouteService.update(route); // 业务更新}} catch (Exception e) {e.printStackTrace();}}
}6、【Nacos控制台】此时通过控制台修改路由的配置项会自动的进行路由更新。 此时可以实现 SpringCloudGateway网关的动态维护处理整个的代码就变为了生产环境下可以使用的操作模型而这样的过程实际上也是一个完善的SpringCloud开发技术的最简化版本了。