Java之a(chǎn)pi網(wǎng)關(guān)斷言及過濾器案例講解
一、什么是api網(wǎng)關(guān)?
所謂的API網(wǎng)關(guān),就是指后臺系統(tǒng)的統(tǒng)一入口,它封裝了應(yīng)用程序的內(nèi)部結(jié)構(gòu),為客戶端提供統(tǒng)一 路由服務(wù),一些與業(yè)務(wù)本身功能無關(guān)的公共邏輯可以在這里實(shí)現(xiàn),諸如認(rèn)證、鑒權(quán)、監(jiān)控、路由轉(zhuǎn)發(fā)等等。
說白了就是通過網(wǎng)關(guān)找服務(wù)。
二、常見的api網(wǎng)關(guān)
Ngnix+lua
使用nginx的反向代理和負(fù)載均衡可實(shí)現(xiàn)對api服務(wù)器的負(fù)載均衡及高可用lua是一種腳本語言,可以來編寫一些簡單的邏輯, nginx支持lua腳本Kong
基于Nginx+Lua開發(fā),性能高,穩(wěn)定,有多個(gè)可用的插件(限流、鑒權(quán)等等)可以開箱即用。問題:只支持Http協(xié)議;二次開發(fā),自由擴(kuò)展困難;提供管理API,缺乏更易用的管控、配置方式。
Zuul Netflix開源的網(wǎng)關(guān),功能豐富,使用JAVA開發(fā),易于二次開發(fā)問題:缺乏管控,無法動態(tài)配置;依賴組件較多;處理Http請求依賴的是Web容器,性能不如Nginx
Spring Cloud Gateway
Spring公司為了替換Zuul而開發(fā)的網(wǎng)關(guān)服務(wù),將在下面具體介紹。
三、使用步驟
1.Spring Cloud Gateway
Spring Cloud Gateway是Spring公司基于Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技術(shù)
開發(fā)的網(wǎng)關(guān),它旨在為微服務(wù)架構(gòu)提供一種簡單有效的統(tǒng)一的 API 路由管理方式。它的目標(biāo)是替代
Netflix Zuul,其不僅提供統(tǒng)一的路由方式,并且基于 Filter 鏈的方式提供了網(wǎng)關(guān)基本的功能,例如:安
全,監(jiān)控和限流。
2.優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
性能強(qiáng)勁:是第一代網(wǎng)關(guān)Zuul的1.6倍
功能強(qiáng)大:內(nèi)置了很多實(shí)用的功能,例如轉(zhuǎn)發(fā)、監(jiān)控、限流等
設(shè)計(jì)優(yōu)雅,容易擴(kuò)展
缺點(diǎn)
其實(shí)現(xiàn)依賴Netty與WebFlux,不是傳統(tǒng)的Servlet編程模型,學(xué)習(xí)成本高
不能將其部署在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 進(jìn)入之前"); filterChain.doFilter(servletRequest,servletResponse); System.out.println("filter 進(jìn)入之后"); } @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)關(guān)--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!--服務(wù)注冊--> <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 使用的是響應(yīng)式的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中獲取服務(wù)信息 routes: - id: share-6002 # 只要唯一標(biāo)識就行 uri: lb://share-6002 #真是的地址 order: 1 predicates: # 滿足斷言中的條件才理由 - Path=/api/share/**,/admin/share/** - id: user-6001 # 只要唯一標(biāo)識就行 uri: lb://user-6001 #真是的地址 order: 1 predicates: # 滿足斷言中的條件才理由 - Path=/api/user/**,/admin/user/**
4.4主程序開啟注解@EnableDiscoveryClient
@EnableDiscoveryClient和@EnableEurekaClient共同點(diǎn)就是:都是能夠讓注冊中心能夠發(fā)現(xiàn),掃描到該服務(wù)。
@EnableEurekaClient只適用于Eureka作為注冊;@EnableDiscoveryClient 可以是其他注冊中心。
代碼如下(示例):
@SpringBootApplication @EnableDiscoveryClient public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class,args); } }
四、執(zhí)行流程
1:基本概念
路由(Route)是 gateway中最基本的組件之一,表示一個(gè)具體的路由信息載體。主要定義了下面幾個(gè)信息:
- | - |
---|---|
id | 路由標(biāo)識符,區(qū)別于其他 Route |
uri | 路由指向的目的地uri,即客戶端請求最終被轉(zhuǎn)發(fā)到的微服務(wù)。 |
order | 用于多個(gè)Route 之間的排序,數(shù)值越小排序越靠前,匹配優(yōu)先級越高。 |
predicate | 斷言的作用是進(jìn)行條件判斷,只有斷言都返回真,才會真正的執(zhí)行路由。 |
filter | 過濾器用于修改請求和響應(yīng)信息。 |
DispatcherHandler:所有請求的調(diào)度器,負(fù)載請求分發(fā)
RoutePredicateHandlerMapping:路由謂語匹配器,用于路由的查找,以及找到路由后返回對應(yīng)的WebHandler,DispatcherHandler會依次遍歷HandlerMapping集合進(jìn)行處理
FilteringWebHandler:使用Filter鏈表處理請求的WebHandler ,
RoutePredicateHandlerMapping找到路由后返回對應(yīng)的FilteringWebHandler對請求進(jìn)行處理,F(xiàn)ilteringWebHandler負(fù)責(zé)組裝Filter鏈表并調(diào)用鏈表處理請求。
五、斷言
Predicate(斷言, 謂詞) 用于進(jìn)行條件判斷,只有斷言都返回真,才會真正的執(zhí)行路由。
斷言就是說: 在 什么條件下 才能進(jìn)行路由轉(zhuǎn)發(fā)
鏈接: http://www.dbjr.com.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: 配置類,用于接收配置文件中的對應(yīng)參數(shù) @Data @NoArgsConstructor public static class Config { private int minAge;//18 對應(yīng)斷言配置中的第一個(gè)參數(shù) private int maxAge;//60 對應(yīng)斷言配置中的第二個(gè)參數(shù) } // 2: 構(gòu)造函數(shù) public AgeRoutePredicateFactory() { super(Config.class); } //3: 讀取配置文件的中參數(shù)值 給他賦值到配置類中的屬性上 public List<String> shortcutFieldOrder() { //這個(gè)位置的順序必須跟配置文件中的值的順序?qū)?yīng) 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 如果不為空,再進(jìn)行路由邏輯判斷 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.
分類:局部過濾器(作用在某一個(gè)路由上)全局過濾器(作用全部路由上)Gateway的Filter從作用范圍可分為兩種: GatewayFilter與GlobalFilter。GatewayFilter:應(yīng)用到單個(gè)路由或者一個(gè)分組的路由上。
GlobalFilter:應(yīng)用到所有的路由上。
內(nèi)置過濾器舉例:
注意要從網(wǎng)關(guān)訪問
自定義局部過濾器
添加自定義Log配置
@Component @Slf4j public class LogGatewayFilterFactory extends AbstractGatewayFilterFactory<LogGatewayFilterFactory.Config> { //1: 配置類 接收配置參數(shù) @Data @NoArgsConstructor public static class Config { private boolean consoleLog; } //2: 構(gòu)造函數(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) { // 進(jìn)入服務(wù)之前 if (config.isConsoleLog()) { log.info("{} 進(jìn)入 {}",new Date(), exchange.getRequest().getPath()); } // 調(diào)用服務(wù) 并且定義服務(wù)回來之后的邏輯 // 注意 如果此時(shí)僅僅只是需要進(jìn)入之前的驗(yàn)證 不需要服務(wù)執(zhí)行完之后的邏輯 可以 return chain.filter(exchange)即可 return chain.filter(exchange).then(Mono.fromRunnable(()->{ if (config.isConsoleLog()) { Long end = System.currentTimeMillis(); log.info("{} 退出 {}. 共耗時(shí):{}",new Date(), exchange.getRequest().getPath(),(end-start)); } })); } }; } }
全局過濾器
全局過濾器作用于所有路由, 無需配置。通過全局過濾器可以實(shí)現(xiàn)對權(quán)限的統(tǒng)一校驗(yàn),安全性驗(yàn)證等功
自定義全局過濾器
//自定義全局過濾器需要實(shí)現(xiàn)GlobalFilter和Ordered接口 @Component public class MyGloablFilter implements GlobalFilter, Ordered { // 過濾邏輯 @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 1 進(jìn)入之前 controller System.out.println("進(jìn)入之前 在 MyGloablFilter"); // 2 放行 return chain.filter(exchange).then(Mono.fromRunnable(() -> { // 在回調(diào)中寫 返回的邏輯 response System.out.println("從controller 回來之后"); })); //3 回調(diào) } // 返回的數(shù)字越小 就越先起作用 @Override public int getOrder() { return 0; } }
到此這篇關(guān)于Java之a(chǎn)pi網(wǎng)關(guān)斷言及過濾器案例講解的文章就介紹到這了,更多相關(guān)Java之a(chǎn)pi網(wǎng)關(guān)斷言及過濾器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java的Spring框架中bean的繼承與內(nèi)部bean的注入
這篇文章主要介紹了Java的Spring框架中bean的繼承與內(nèi)部bean的注入,Spring框架是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下2015-12-12SpringCloud OpenFeign自定義結(jié)果解碼器方式
這篇文章主要介紹了SpringCloud OpenFeign自定義結(jié)果解碼器方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09詳解spring boot整合JMS(ActiveMQ實(shí)現(xiàn))
本篇文章主要介紹了詳解spring boot整合JMS(ActiveMQ實(shí)現(xiàn)),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10zookeeper實(shí)戰(zhàn)之實(shí)現(xiàn)分布式鎖的方法
Zookeeper實(shí)現(xiàn)分布式鎖比Redis簡單,Zookeeper有一個(gè)特性,多個(gè)線程在Zookeeper里創(chuàng)建同一個(gè)節(jié)點(diǎn)時(shí),只有一個(gè)線程執(zhí)行成功,Zookeeper主要是利用臨時(shí)有序節(jié)點(diǎn)這一特性實(shí)現(xiàn)分布式鎖,感興趣的朋友跟隨小編一起學(xué)習(xí)吧2022-11-11Maven里面沒有plugins dependence問題解決
在整合Nacos和Dubbo時(shí),出現(xiàn)Maven錯(cuò)誤可以通過檢查父模塊的依賴解決,問題源于MySQL驅(qū)動版本不兼容,移除特定依賴并刷新pom文件可恢復(fù)項(xiàng)目,執(zhí)行clean命令,查看報(bào)錯(cuò),感興趣的可以了解一下2024-10-10Spring如何基于注解顯式實(shí)現(xiàn)自動裝配
這篇文章主要介紹了Spring如何基于注解顯式實(shí)現(xiàn)自動裝配,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08