Reputation: 520878
We are attempting to use Spring Cloud Gateway to setup a microservice based architecture. Currently, we have defined a route programatically:
@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();
}
}
The above would route an incoming request /status
via GET to another endpoint. We would like to apply a custom filter, which we have implemented in AuthorizationFilter
. This filter, as the name implies, is another microservice which will either allow or deny an incoming request based on credentials and permissions.
Currently, the pattern we are following, which works, is to inject a Spring RestTemplate
into the gateway class above, and then to pass this RestTemplate
to the constructor of the filter.
However, how can this be done if we wanted to switch to using a YAML file for defining all the routes? Presumably in both cases Spring would be constructing a new filter for each incoming request. But in the case of YAML, how can we pass something in the construtor? If this cannot be done, is there any other way to inject a RestTemplate
, or any other resource into a custom Spring gateway filter?
Upvotes: 2
Views: 4439
Reputation: 44665
You can register your own custom GatewayFilterFactory
. This allows you to provide a custom configuration, and within that configuration, you can use SpEL to reference a bean.
For example:
@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
}
}
Now you can use SpEL to properly reference a RestTemplate
bean:
spring:
cloud:
gateway:
routes:
- id: status
uri: http://localhost:8081/
filters:
- name: Authentication
args:
restTemplate: "#{@nameOfRestTemplateBean}"
predicates:
- Path=/status
Alternatively, you could inject a RestTemplate
bean within your gateway filter. For example:
@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
}
}
The code/configuration necessary to do the inject is less complex, but it also makes it more difficult if you ever decide to put AuthenticationGatewayFilterFactory
in a separate library, as the "consumers" of this library won't have any control over which RestTemplate
is being injected.
Upvotes: 3