Java之api網(wǎng)關斷言及過濾器案例講解
一、什么是api網(wǎng)關?
所謂的API網(wǎng)關,就是指后臺系統(tǒng)的統(tǒng)一入口,它封裝了應用程序的內部結構,為客戶端提供統(tǒng)一 路由服務,一些與業(yè)務本身功能無關的公共邏輯可以在這里實現(xiàn),諸如認證、鑒權、監(jiān)控、路由轉發(fā)等等。
說白了就是通過網(wǎng)關找服務。


二、常見的api網(wǎng)關
Ngnix+lua
使用nginx的反向代理和負載均衡可實現(xiàn)對api服務器的負載均衡及高可用lua是一種腳本語言,可以來編寫一些簡單的邏輯, nginx支持lua腳本Kong
基于Nginx+Lua開發(fā),性能高,穩(wěn)定,有多個可用的插件(限流、鑒權等等)可以開箱即用。問題:只支持Http協(xié)議;二次開發(fā),自由擴展困難;提供管理API,缺乏更易用的管控、配置方式。
Zuul Netflix開源的網(wǎng)關,功能豐富,使用JAVA開發(fā),易于二次開發(fā)問題:缺乏管控,無法動態(tài)配置;依賴組件較多;處理Http請求依賴的是Web容器,性能不如Nginx
Spring Cloud Gateway
Spring公司為了替換Zuul而開發(fā)的網(wǎng)關服務,將在下面具體介紹。
三、使用步驟

1.Spring Cloud Gateway
Spring Cloud Gateway是Spring公司基于Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技術
開發(fā)的網(wǎng)關,它旨在為微服務架構提供一種簡單有效的統(tǒng)一的 API 路由管理方式。它的目標是替代
Netflix Zuul,其不僅提供統(tǒng)一的路由方式,并且基于 Filter 鏈的方式提供了網(wǎng)關基本的功能,例如:安
全,監(jiān)控和限流。
2.優(yōu)缺點
優(yōu)點
性能強勁:是第一代網(wǎng)關Zuul的1.6倍
功能強大:內置了很多實用的功能,例如轉發(fā)、監(jiān)控、限流等
設計優(yōu)雅,容易擴展
缺點
其實現(xiàn)依賴Netty與WebFlux,不是傳統(tǒng)的Servlet編程模型,學習成本高
不能將其部署在Tomcat、Jetty等Servlet容器里,只能打成jar包執(zhí)行
需要Spring Boot 2.0及以上的版本,才支持
3.傳統(tǒng)的過濾器
代碼如下(示例):
@WebFilter(filterName="MyFliter",urlPatterns="/api/share/*")
public class MyFliter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("filter 進入之前");
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("filter 進入之后");
}
@Override
public void destroy() {
}
}
//在主程序處加上注解
//@ServletComponentScan("過濾器包名")
4.使用gateway
4.1module

4.2添加pom依賴
代碼如下(示例):
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud_nacos</artifactId>
<groupId>com.csdn</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud_gateway</artifactId>
<dependencies>
<!--限流算法使用redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<!--網(wǎng)關-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--服務注冊-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.csdn</groupId>
<artifactId>springcloud_common</artifactId>
<version>${project.version}</version>
<!--gateway 使用的是響應式的web編程模式 我們要把傳統(tǒng)的web編程模型刨除-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4.3yaml配置
代碼如下(示例):
server:
port: 7000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848 # 將gateway注冊到nacos
gateway:
discovery:
locator:
enabled: true # 讓gateway從nacos中獲取服務信息
routes:
- id: share-6002 # 只要唯一標識就行
uri: lb://share-6002 #真是的地址
order: 1
predicates: # 滿足斷言中的條件才理由
- Path=/api/share/**,/admin/share/**
- id: user-6001 # 只要唯一標識就行
uri: lb://user-6001 #真是的地址
order: 1
predicates: # 滿足斷言中的條件才理由
- Path=/api/user/**,/admin/user/**
4.4主程序開啟注解@EnableDiscoveryClient
@EnableDiscoveryClient和@EnableEurekaClient共同點就是:都是能夠讓注冊中心能夠發(fā)現(xiàn),掃描到該服務。
@EnableEurekaClient只適用于Eureka作為注冊;@EnableDiscoveryClient 可以是其他注冊中心。
代碼如下(示例):
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class,args);
}
}
四、執(zhí)行流程
1:基本概念
路由(Route)是 gateway中最基本的組件之一,表示一個具體的路由信息載體。主要定義了下面幾個信息:
| - | - |
|---|---|
| id | 路由標識符,區(qū)別于其他 Route |
| uri | 路由指向的目的地uri,即客戶端請求最終被轉發(fā)到的微服務。 |
| order | 用于多個Route 之間的排序,數(shù)值越小排序越靠前,匹配優(yōu)先級越高。 |
| predicate | 斷言的作用是進行條件判斷,只有斷言都返回真,才會真正的執(zhí)行路由。 |
| filter | 過濾器用于修改請求和響應信息。 |

DispatcherHandler:所有請求的調度器,負載請求分發(fā)
RoutePredicateHandlerMapping:路由謂語匹配器,用于路由的查找,以及找到路由后返回對應的WebHandler,DispatcherHandler會依次遍歷HandlerMapping集合進行處理
FilteringWebHandler:使用Filter鏈表處理請求的WebHandler ,
RoutePredicateHandlerMapping找到路由后返回對應的FilteringWebHandler對請求進行處理,F(xiàn)ilteringWebHandler負責組裝Filter鏈表并調用鏈表處理請求。
五、斷言
Predicate(斷言, 謂詞) 用于進行條件判斷,只有斷言都返回真,才會真正的執(zhí)行路由。
斷言就是說: 在 什么條件下 才能進行路由轉發(fā)
鏈接: http://chabaoo.cn/article/219232.htm
5.1: 自定義斷言
添加自定義斷言類
package gateway.pradicate;
import com.alibaba.nacos.common.utils.StringUtils;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
@Component
public class AgeRoutePredicateFactory extends AbstractRoutePredicateFactory<AgeRoutePredicateFactory.Config> {
// 1: 配置類,用于接收配置文件中的對應參數(shù)
@Data
@NoArgsConstructor
public static class Config {
private int minAge;//18 對應斷言配置中的第一個參數(shù)
private int maxAge;//60 對應斷言配置中的第二個參數(shù)
}
// 2: 構造函數(shù)
public AgeRoutePredicateFactory() {
super(Config.class);
}
//3: 讀取配置文件的中參數(shù)值 給他賦值到配置類中的屬性上
public List<String> shortcutFieldOrder() {
//這個位置的順序必須跟配置文件中的值的順序對應
return Arrays.asList("minAge", "maxAge");
}
//4: 斷言邏輯
public Predicate<ServerWebExchange> apply(Config config) {
return new Predicate<ServerWebExchange>() {
@Override
public boolean test(ServerWebExchange serverWebExchange) {
// 4.1 接收前臺傳入的age參數(shù)
String ageStr = serverWebExchange.getRequest().getQueryParams().getFirst("Age");
//4.2 先判斷是否為空
if (StringUtils.isNotEmpty(ageStr)) {
//3 如果不為空,再進行路由邏輯判斷
int age = Integer.parseInt(ageStr);
if (age < config.getMaxAge() && age > config.getMinAge()) {
return true;
} else {
return false;
}
}
return false;
}
};
}
}
在需要判斷的的routes下配置

5.2: 過濾器
鏈接: https://www.cnblogs.com/fx-blog/p/11751977.html.
分類:局部過濾器(作用在某一個路由上)全局過濾器(作用全部路由上)Gateway的Filter從作用范圍可分為兩種: GatewayFilter與GlobalFilter。GatewayFilter:應用到單個路由或者一個分組的路由上。
GlobalFilter:應用到所有的路由上。

內置過濾器舉例:

注意要從網(wǎng)關訪問
自定義局部過濾器

添加自定義Log配置
@Component
@Slf4j
public class LogGatewayFilterFactory
extends AbstractGatewayFilterFactory<LogGatewayFilterFactory.Config> {
//1: 配置類 接收配置參數(shù)
@Data
@NoArgsConstructor
public static class Config {
private boolean consoleLog;
}
//2: 構造函數(shù)【固定寫法】
public LogGatewayFilterFactory() {
super(Config.class);
}
//3: 讀取配置文件中的參數(shù) 賦值到 配置類中
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("consoleLog");
}
//4: 過濾器邏輯
@Override
public GatewayFilter apply(Config config) {
return new GatewayFilter() {
Long start = System.currentTimeMillis();
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 進入服務之前
if (config.isConsoleLog()) {
log.info("{} 進入 {}",new Date(), exchange.getRequest().getPath());
}
// 調用服務 并且定義服務回來之后的邏輯
// 注意 如果此時僅僅只是需要進入之前的驗證 不需要服務執(zhí)行完之后的邏輯 可以 return chain.filter(exchange)即可
return chain.filter(exchange).then(Mono.fromRunnable(()->{
if (config.isConsoleLog()) {
Long end = System.currentTimeMillis();
log.info("{} 退出 {}. 共耗時:{}",new Date(), exchange.getRequest().getPath(),(end-start));
}
}));
}
};
}
}
全局過濾器
全局過濾器作用于所有路由, 無需配置。通過全局過濾器可以實現(xiàn)對權限的統(tǒng)一校驗,安全性驗證等功

自定義全局過濾器
//自定義全局過濾器需要實現(xiàn)GlobalFilter和Ordered接口
@Component
public class MyGloablFilter implements GlobalFilter, Ordered {
// 過濾邏輯
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1 進入之前 controller
System.out.println("進入之前 在 MyGloablFilter");
// 2 放行
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
// 在回調中寫 返回的邏輯 response
System.out.println("從controller 回來之后");
}));
//3 回調
}
// 返回的數(shù)字越小 就越先起作用
@Override
public int getOrder() {
return 0;
}
}
到此這篇關于Java之api網(wǎng)關斷言及過濾器案例講解的文章就介紹到這了,更多相關Java之api網(wǎng)關斷言及過濾器內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java中使用Files類的copy()方法實現(xiàn)復制文件
這篇文章主要介紹了Java中使用Files類的copy()方法實現(xiàn)復制文件,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-05-05
Springboot登錄驗證的統(tǒng)一攔截處理的實現(xiàn)
如果不進行統(tǒng)一的攔截處理,每次用戶請求你都要去進行用戶的信息驗證,所以本文主要介紹了Springboot登錄驗證的統(tǒng)一攔截處理的實現(xiàn),感興趣的可以了解一下,感興趣的可以了解一下2023-09-09

