Spring Cloud Gateway将bean传递到自定义过滤器

时间:2019-03-28 09:10:20

标签: spring-boot filter dependency-injection spring-cloud-gateway

我们正在尝试使用Spring Cloud Gateway设置基于微服务的架构。目前,我们已通过编程方式定义了一条路线:

@ServletComponentScan
@SpringBootApplication
public class GatewayApplication {
    // to be passed to and used by custom filter
    @Autowired
    RestTemplate restTemplate;

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

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
        .route("status", r -> r
            .method(HttpMethod.GET)
            .and()
            .path("/status")
            .filters(f -> f.rewritePath("/status", "/v2/status")
                           .filter(new AuthorizationFilter(restTemplate).apply(new Config(""))))
            .uri("http://localhost:8081/"))
        .build();
    }
}

以上内容将通过GET将传入请求/status路由到另一个端点。我们想应用一个自定义过滤器,该过滤器已在AuthorizationFilter中实现。顾名思义,该过滤器是另一个微服务,它将基于凭据和权限来允许或拒绝传入的请求。

当前,我们遵循的模式有效,是将Spring RestTemplate注入上述网关类,然后将此RestTemplate传递给过滤器的构造函数。

但是,如果我们想切换到使用YAML文件来定义所有路由,该怎么办?大概在两种情况下,Spring都会为每个传入的请求构造一个新的过滤器。但是对于YAML,我们如何在构造函数中传递某些内容?如果无法做到这一点,是否还有其他方法可以将RestTemplate或任何其他资源注入到自定义的Spring网关过滤器中?

1 个答案:

答案 0 :(得分:1)

您可以register your own custom GatewayFilterFactory。这样就可以提供自定义配置,并且在该配置中,可以使用SpEL来引用bean。

例如:

@Component
public class AuthenticationGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthenticationGatewayFilterFactory.Config> {
    public AuthenticationGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        // TODO: Implement
    }

    public static class Config {
        private RestTemplate restTemplate;

        // TODO: Getters + Setters
    }
}

现在,您可以使用SpEL正确引用RestTemplate bean:

spring:
  cloud:
    gateway:
      routes:
        - id: status
          uri: http://localhost:8081/
          filters:
            - name: Authentication
              args:
                restTemplate: "#{@nameOfRestTemplateBean}"
          predicates:
            - Path=/status

或者,您可以在网关过滤器中注入RestTemplate bean。例如:

@Component
public class AuthenticationGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthenticationGatewayFilterFactory.Config> {
    private RestTemplate restTemplate;

    public AuthenticationGatewayFilterFactory(RestTemplate restTemplate) {
        super(Config.class);
        this.restTemplate = restTemplate;
    }

    @Override
    public GatewayFilter apply(Config config) {
        // TODO: Implement
    }

    public static class Config {
        // TODO: Implement
    }
}

进行注入所需的代码/配置不太复杂,但是如果您决定将AuthenticationGatewayFilterFactory放在一个单独的库中,这也会增加难度,因为该库的“消费者”不会可以控制注入哪个RestTemplate