spring-cloud-gateway-core-2.0.0.RC1-sources.jar!/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java
@Configuration @ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true) @EnableConfigurationProperties @AutoConfigureBefore(HttpHandlerAutoConfiguration.class) @AutoConfigureAfter({GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class}) @ConditionalOnClass(DispatcherHandler.class) public class GatewayAutoConfiguration { //...... @Bean public AfterRoutePredicateFactory afterRoutePredicateFactory() { return new AfterRoutePredicateFactory(); } @Bean public BeforeRoutePredicateFactory beforeRoutePredicateFactory() { return new BeforeRoutePredicateFactory(); } @Bean public BetweenRoutePredicateFactory betweenRoutePredicateFactory() { return new BetweenRoutePredicateFactory(); } @Bean public CookieRoutePredicateFactory cookieRoutePredicateFactory() { return new CookieRoutePredicateFactory(); } @Bean public HeaderRoutePredicateFactory headerRoutePredicateFactory() { return new HeaderRoutePredicateFactory(); } @Bean public HostRoutePredicateFactory hostRoutePredicateFactory() { return new HostRoutePredicateFactory(); } @Bean public MethodRoutePredicateFactory methodRoutePredicateFactory() { return new MethodRoutePredicateFactory(); } @Bean public PathRoutePredicateFactory pathRoutePredicateFactory() { return new PathRoutePredicateFactory(); } @Bean public QueryRoutePredicateFactory queryRoutePredicateFactory() { return new QueryRoutePredicateFactory(); } @Bean public ReadBodyPredicateFactory readBodyPredicateFactory(ServerCodecConfigurer codecConfigurer) { return new ReadBodyPredicateFactory(codecConfigurer); } //...... @Configuration @ConditionalOnClass(Health.class) protected static class GatewayActuatorConfiguration { @Bean @ConditionalOnEnabledEndpoint public GatewayControllerEndpoint gatewayControllerEndpoint(RouteDefinitionLocator routeDefinitionLocator, List<GlobalFilter> globalFilters, List<GatewayFilterFactory> GatewayFilters, RouteDefinitionWriter routeDefinitionWriter, RouteLocator routeLocator) { return new GatewayControllerEndpoint(routeDefinitionLocator, globalFilters, GatewayFilters, routeDefinitionWriter, routeLocator); } } }
可以看到最后有一个GatewayActuatorConfiguration,在有actuator类库的前提下则会配置,配置的是GatewayControllerEndpoint
spring-cloud-gateway-core-2.0.0.RC1-sources.jar!/org/springframework/cloud/gateway/actuate/GatewayControllerEndpoint.java
@RestControllerEndpoint(id = "gateway") public class GatewayControllerEndpoint implements ApplicationEventPublisherAware { private static final Log log = LogFactory.getLog(GatewayControllerEndpoint.class); private RouteDefinitionLocator routeDefinitionLocator; private List<GlobalFilter> globalFilters; private List<GatewayFilterFactory> GatewayFilters; private RouteDefinitionWriter routeDefinitionWriter; private RouteLocator routeLocator; private ApplicationEventPublisher publisher; public GatewayControllerEndpoint(RouteDefinitionLocator routeDefinitionLocator, List<GlobalFilter> globalFilters, List<GatewayFilterFactory> GatewayFilters, RouteDefinitionWriter routeDefinitionWriter, RouteLocator routeLocator) { this.routeDefinitionLocator = routeDefinitionLocator; this.globalFilters = globalFilters; this.GatewayFilters = GatewayFilters; this.routeDefinitionWriter = routeDefinitionWriter; this.routeLocator = routeLocator; } @Override public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { this.publisher = publisher; } // TODO: Add uncommited or new but not active routes endpoint @PostMapping("/refresh") public Mono<Void> refresh() { this.publisher.publishEvent(new RefreshRoutesEvent(this)); return Mono.empty(); } @GetMapping("/globalfilters") public Mono<HashMap<String, Object>> globalfilters() { return getNamesToOrders(this.globalFilters); } @GetMapping("/routefilters") public Mono<HashMap<String, Object>> routefilers() { return getNamesToOrders(this.GatewayFilters); } private <T> Mono<HashMap<String, Object>> getNamesToOrders(List<T> list) { return Flux.fromIterable(list).reduce(new HashMap<>(), this::putItem); } private HashMap<String, Object> putItem(HashMap<String, Object> map, Object o) { Integer order = null; if (o instanceof Ordered) { order = ((Ordered)o).getOrder(); } //filters.put(o.getClass().getName(), order); map.put(o.toString(), order); return map; } // TODO: Flush out routes without a definition @GetMapping("/routes") public Mono<List<Map<String, Object>>> routes() { Mono<Map<String, RouteDefinition>> routeDefs = this.routeDefinitionLocator.getRouteDefinitions() .collectMap(RouteDefinition::getId); Mono<List<Route>> routes = this.routeLocator.getRoutes().collectList(); return Mono.zip(routeDefs, routes).map(tuple -> { Map<String, RouteDefinition> defs = tuple.getT1(); List<Route> routeList = tuple.getT2(); List<Map<String, Object>> allRoutes = new ArrayList<>(); routeList.forEach(route -> { HashMap<String, Object> r = new HashMap<>(); r.put("route_id", route.getId()); r.put("order", route.getOrder()); if (defs.containsKey(route.getId())) { r.put("route_definition", defs.get(route.getId())); } else { HashMap<String, Object> obj = new HashMap<>(); obj.put("predicate", route.getPredicate().toString()); if (!route.getFilters().isEmpty()) { ArrayList<String> filters = new ArrayList<>(); for (GatewayFilter filter : route.getFilters()) { filters.add(filter.toString()); } obj.put("filters", filters); } if (!obj.isEmpty()) { r.put("route_object", obj); } } allRoutes.add(r); }); return allRoutes; }); } /* http POST :8080/admin/gateway/routes/apiaddreqhead uri=http://httpbin.org:80 predicates:='["Host=**.apiaddrequestheader.org", "Path=/headers"]' filters:='["AddRequestHeader=X-Request-ApiFoo, ApiBar"]' */ @PostMapping("/routes/{id}") @SuppressWarnings("unchecked") public Mono<ResponseEntity<Void>> save(@PathVariable String id, @RequestBody Mono<RouteDefinition> route) { return this.routeDefinitionWriter.save(route.map(r -> { r.setId(id); log.debug("Saving route: " + route); return r; })).then(Mono.defer(() -> Mono.just(ResponseEntity.created(URI.create("/routes/"+id)).build()) )); } @DeleteMapping("/routes/{id}") public Mono<ResponseEntity<Object>> delete(@PathVariable String id) { return this.routeDefinitionWriter.delete(Mono.just(id)) .then(Mono.defer(() -> Mono.just(ResponseEntity.ok().build()))) .onErrorResume(t -> t instanceof NotFoundException, t -> Mono.just(ResponseEntity.notFound().build())); } @GetMapping("/routes/{id}") public Mono<ResponseEntity<RouteDefinition>> route(@PathVariable String id) { //TODO: missing RouteLocator return this.routeDefinitionLocator.getRouteDefinitions() .filter(route -> route.getId().equals(id)) .singleOrEmpty() .map(route -> ResponseEntity.ok(route)) .switchIfEmpty(Mono.just(ResponseEntity.notFound().build())); } @GetMapping("/routes/{id}/combinedfilters") public Mono<HashMap<String, Object>> combinedfilters(@PathVariable String id) { //TODO: missing global filters return this.routeLocator.getRoutes() .filter(route -> route.getId().equals(id)) .reduce(new HashMap<>(), this::putItem); } }
可以看到提供了如下几个rest api
[ { "route_id": "CompositeDiscoveryClient_DISCOVERY-SERVICE", "route_definition": { "id": "CompositeDiscoveryClient_DISCOVERY-SERVICE", "predicates": [ { "name": "Path", "args": { "pattern": "/DISCOVERY-SERVICE/**" } } ], "filters": [ { "name": "RewritePath", "args": { "regexp": "/DISCOVERY-SERVICE/(?<remaining>.*)", "replacement": "/${remaining}" } } ], "uri": "lb://DISCOVERY-SERVICE", "order": 0 }, "order": 0 }, { "route_id": "CompositeDiscoveryClient_GATEWAY-SERVICE", "route_definition": { "id": "CompositeDiscoveryClient_GATEWAY-SERVICE", "predicates": [ { "name": "Path", "args": { "pattern": "/GATEWAY-SERVICE/**" } } ], "filters": [ { "name": "RewritePath", "args": { "regexp": "/GATEWAY-SERVICE/(?<remaining>.*)", "replacement": "/${remaining}" } } ], "uri": "lb://GATEWAY-SERVICE", "order": 0 }, "order": 0 } ]
{ "org.springframework.cloud.gateway.filter.LoadBalancerClientFilter@f425231": 10100, "org.springframework.cloud.gateway.filter.NettyWriteResponseFilter@5cbd94b2": -1, "org.springframework.cloud.gateway.filter.NettyRoutingFilter@506aabf6": 2147483647, "org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@756aadfc": 10000, "org.springframework.cloud.gateway.filter.ForwardRoutingFilter@705a8dbc": 2147483647, "org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@6824b913": 2147483637, "org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@40729f01": 2147483646 }
{ "[RedirectToGatewayFilterFactory@32f96bba configClass = RedirectToGatewayFilterFactory.Config]": null, "[StripPrefixGatewayFilterFactory@4a481728 configClass = StripPrefixGatewayFilterFactory.Config]": null, "[RemoveResponseHeaderGatewayFilterFactory@67e25252 configClass = AbstractGatewayFilterFactory.NameConfig]": null, "[RequestHeaderToRequestUriGatewayFilterFactory@4ace284d configClass = AbstractGatewayFilterFactory.NameConfig]": null, "[ModifyRequestBodyGatewayFilterFactory@b3e86d5 configClass = ModifyRequestBodyGatewayFilterFactory.Config]": null, "[RemoveRequestHeaderGatewayFilterFactory@611640f0 configClass = AbstractGatewayFilterFactory.NameConfig]": null, "[SetStatusGatewayFilterFactory@3fd05b3e configClass = SetStatusGatewayFilterFactory.Config]": null, "[PreserveHostHeaderGatewayFilterFactory@4d0e54e0 configClass = Object]": null, "[SetResponseHeaderGatewayFilterFactory@1682c08c configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]": null, "[SecureHeadersGatewayFilterFactory@76ececd configClass = Object]": null, "[SaveSessionGatewayFilterFactory@4eb9f2af configClass = Object]": null, "[AddResponseHeaderGatewayFilterFactory@75b6dd5b configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]": null, "[PrefixPathGatewayFilterFactory@e111c7c configClass = PrefixPathGatewayFilterFactory.Config]": null, "[SetRequestHeaderGatewayFilterFactory@7affc159 configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]": null, "[RewritePathGatewayFilterFactory@58f4b31a configClass = RewritePathGatewayFilterFactory.Config]": null, "[SetPathGatewayFilterFactory@72eb6200 configClass = SetPathGatewayFilterFactory.Config]": null, "[RetryGatewayFilterFactory@21a9a705 configClass = RetryGatewayFilterFactory.Retry]": null, "[AddRequestHeaderGatewayFilterFactory@1f1cddf3 configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]": null, "[ModifyResponseBodyGatewayFilterFactory@72b43104 configClass = ModifyResponseBodyGatewayFilterFactory.Config]": null, "[AddRequestParameterGatewayFilterFactory@228bda54 configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]": null }
{ "id": "CompositeDiscoveryClient_DISCOVERY-SERVICE", "predicates": [ { "name": "Path", "args": { "pattern": "/DISCOVERY-SERVICE/**" } } ], "filters": [ { "name": "RewritePath", "args": { "regexp": "/DISCOVERY-SERVICE/(?<remaining>.*)", "replacement": "/${remaining}" } } ], "uri": "lb://DISCOVERY-SERVICE", "order": 0 }
{ "Route{id='CompositeDiscoveryClient_DISCOVERY-SERVICE', uri=lb://DISCOVERY-SERVICE, order=0, predicate=org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$769/1774209584@7d9639ad, gatewayFilters=[OrderedGatewayFilter{delegate=org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory$$Lambda$771/1052389952@528c8627, order=1}]}": 0 }