前言
最近在SpringCloudGateway網(wǎng)關(guān)加上動態(tài)路由和限流的功能,使用RequestRateLimiter配置令牌桶時,啟動應(yīng)用報(bào)了異常,異常信息為Unable to find GatewayFilterFactory with name RequestRateLimiter

原因是:引入
org.springframework.boot:spring-boot-starter-data-redis-reactive
依賴時,排除了lettuce-core依賴(當(dāng)時一個同事使用Lettuce操作Redis遇到問題,排除這個依賴使用Jedis了),導(dǎo)致生成RequestRateLimiterGatewayFilterFactory實(shí)例的時候生成不了,但是項(xiàng)目中又配置了限流,導(dǎo)致獲取限流的Factory獲取不到。
刪除掉排除的lettuce-core依賴即可恢復(fù)正常。
定位過程
看到一個異常,一般先根據(jù)異常堆棧找到報(bào)錯的代碼,然后再報(bào)錯代碼附近打上斷點(diǎn)進(jìn)行Debug,根據(jù)報(bào)錯信息往上一層層推,有一部分可能源碼調(diào)用鏈嵌套很多,很難找出報(bào)錯的代碼,另一種方法就是根據(jù)報(bào)錯的Message直接搜項(xiàng)目代碼(包括Jar包里面,搜索不能完全用報(bào)錯信息搜,拷貝部分報(bào)錯信息,因?yàn)橛行┦亲兞科唇拥模徊糠忠徊糠衷嚕?/p>
在這個問題里面,我是直接搜索異常信息,搜索 Unable to find

發(fā)現(xiàn)是在 RouteDefinitionRouteLocator類的loadGatewayFilters方法中,直接打上斷點(diǎn)去調(diào)試

fatory是從當(dāng)前類的gatewayFilterFactories中去取的,然后看下這個屬性是如何初始化的

這個屬性也是從其他類傳進(jìn)來的,只是將傳進(jìn)來的GatewayFilterFactory的List轉(zhuǎn)成Map,在往上看

是在GatewayAutoConfiguration配置類里面進(jìn)行實(shí)例化RouteDefinitionRouteLocator類的,所以gatewayFilters是每個GatewayFilterFactory通過配置導(dǎo)入到Spring容器的,我們直接看限流使用到的RequestRateLimiterGatewayFilterFactory是在哪配置的,搜索這個類使用情況,發(fā)現(xiàn)是在GatewayAutoConfiguration類中配置的,配置代碼如下

可以看到這里注入和很多(截圖只截了三個)GatewayFilterFactory,RequestRateLimiterGatewayFilterFactory這個Bean的實(shí)例化是依賴RateLimiter的,因?yàn)橄蘖髂J(rèn)是使用Redis的,直接看RedisRateLimiter這個類的配置,搜索這個類的使用情況,是在GatewayRedisAutoConfiguration類中配置的

RedisRateLimiter這個Bean又依賴ReactiveStringRedisTemplate,ReactiveStringRedisTemplate這個類是在RedisReactiveAutoConfiguration類中配置的

ReactiveStringRedisTemplate又依賴于ReactiveRedisConnectionFactory,這個Redis連接工廠唯一的實(shí)現(xiàn)類是LettuceConnectionFactory,LettuceConnectionFactory是基于Lettuce的,所以這個bean是不會實(shí)例化的,層層依賴導(dǎo)致RequestRateLimiterGatewayFilterFactory創(chuàng)建不了實(shí)例。
總結(jié)
遇到問題及時解決,不應(yīng)該在項(xiàng)目中留下隱患,可能會給其他人員帶來很大的技術(shù)債。
解決問題時一步步調(diào)試,多DEBUG,DEBUG過程中會對變量、方法調(diào)用過程有更清晰的認(rèn)識,比如剛開始拋異常時,new RequestRateLimiterGatewayFilterFactory這句代碼是不會跑的,即使打了斷點(diǎn),但是new其他的GatewayFilterFactory我也打了斷點(diǎn)試了,卻是會跑的,就把方向放在了RequestRateLimiterGatewayFilterFactory這個類的實(shí)例化上,再一步步往下調(diào),所以我截圖上代碼基本都是有斷點(diǎn)的。