You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GatewayFilter注入Feign Client引发循环依赖问题求解决方案

问题描述

在网关过滤器的校验环节中,我需要调用微服务接口。当我将Feign Client(UserApi)注入GatewayFilter实现类SecurityFilter后,出现了如下循环依赖错误,即使已开启允许循环引用仍无法解决,请问该如何处理?

错误信息

描述:

应用上下文部分Bean的依赖形成了循环:

┌─────┐
| securityFilter(定义在文件[/target/classes/com/example/SecurityFilter.class])
↑ ↓
| cachedCompositeRouteLocator(定义在类路径资源[org/springframework/cloud/gateway/config/GatewayAutoConfiguration.class])
↑ ↓
| routeDefinitionRouteLocator(定义在类路径资源[org/springframework/cloud/gateway/config/GatewayAutoConfiguration.class])
└─────┘

解决方案建议:

尽管已允许循环引用,但仍无法打破Bean之间的依赖循环。请更新应用以移除该依赖循环。

GatewayFilter实现类

@Component
public class SecurityFilter implements GatewayFilterFactory<SecurityFilter.Config> {

    private final UserApi userApi;

    public SecurityFilter(UserApi userApi) {
        this.userApi = userApi;
    }

    @Override
    public GatewayFilter apply(Config config) {
        return ((exchange, chain) -> {
            return chain.filter(exchange.mutate().request(exchange.getRequest()).build());
        });
    }

    @Override
    public Class<Config> getConfigClass() {
        return Config.class;
    }

    @Override
    public Config newConfig() {
        Config c = new Config();
        return c;
    }

    public static class Config {
    }
}

pom.xml

<properties>
        <java.version>17</java.version>
        <spring-cloud.version>2021.0.3</spring-cloud.version>
    </properties>
    <dependencies>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>4.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

主启动类

@SpringBootApplication
@ComponentScan("com.example")
@EnableFeignClients(basePackages = {"com.example.feign"})
public class GatewayApplicationMain {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplicationMain.class, args);
    }
}

Feign API接口

@FeignClient(name = "user", path="userService/", url="http://localhost:8091/")
public interface UserApi {
    @GetMapping("/getUserByUserName/{userName}")
    ResponseEntity<Object> getUserByUserName(@PathVariable(name = "userName") String userName);
}

安全配置类

@Configuration
public class SecurityConfig {
    @Bean
    public SecurityWebFilterChain configure(ServerHttpSecurity http) {
        http.csrf().disable()
                .authorizeExchange()
                .anyExchange()
                .authenticated()
                .and()
                .oauth2Login()
                .and().oauth2ResourceServer().jwt();
        return http.build();
    }
}

application.properties配置文件

server.port=8090
spring.main.allow-circular-references=true

解决方案

这个循环依赖的核心原因是:GatewayFilterFactory类型的Bean会被网关自动加载到路由定位器的依赖链中,而构造注入UserApi(Feign客户端)的方式,导致启动时Bean初始化顺序冲突,即使开启循环引用也无法解决。可以通过以下几种方式处理:

1. 延迟注入Feign客户端

给UserApi的注入添加@Lazy注解,延迟Feign客户端的初始化时机,避免在网关Bean初始化阶段就触发依赖加载:

@Component
public class SecurityFilter implements GatewayFilterFactory<SecurityFilter.Config> {

    private final UserApi userApi;

    public SecurityFilter(@Lazy UserApi userApi) {
        this.userApi = userApi;
    }

    // 其余代码不变
}

2. 改用Setter注入

将构造注入改为Setter注入,让Spring先初始化SecurityFilter,再注入UserApi,打破循环依赖链:

@Component
public class SecurityFilter implements GatewayFilterFactory<SecurityFilter.Config> {

    private UserApi userApi;

    @Autowired
    public void setUserApi(UserApi userApi) {
        this.userApi = userApi;
    }

    // 其余代码不变
}

3. 过滤器执行时动态获取Feign客户端

不在Bean初始化阶段注入UserApi,而是在过滤器实际执行时,从Spring上下文动态获取:

@Component
public class SecurityFilter implements GatewayFilterFactory<SecurityFilter.Config> {

    private final ApplicationContext context;

    public SecurityFilter(ApplicationContext context) {
        this.context = context;
    }

    @Override
    public GatewayFilter apply(Config config) {
        return ((exchange, chain) -> {
            // 调用接口时再获取UserApi实例
            UserApi userApi = context.getBean(UserApi.class);
            // 执行你的校验逻辑
            return chain.filter(exchange);
        });
    }

    // 其余代码不变
}

4. 使用WebClient替代Feign

Gateway是响应式架构,推荐用WebClient直接调用微服务,避免Feign客户端的Bean初始化冲突:

@Component
public class SecurityFilter implements GatewayFilterFactory<SecurityFilter.Config> {

    private final WebClient webClient;

    public SecurityFilter(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder.baseUrl("http://localhost:8091/userService/").build();
    }

    @Override
    public GatewayFilter apply(Config config) {
        return ((exchange, chain) -> {
            // 用WebClient调用接口
            return webClient.get()
                    .uri("/getUserByUserName/{userName}", "test")
                    .retrieve()
                    .bodyToMono(Object.class)
                    .flatMap(result -> {
                        // 处理返回结果
                        return chain.filter(exchange);
                    });
        });
    }

    // 其余代码不变
}

内容的提问来源于stack exchange,提问作者kernel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 20:16:06