Core source code
Route class
Route is one of the most basic components in gateway, which represents a specific routing information carrier. The routing information consists of an ID, a target URl, a set of assertions, and a set of filters. If the asserted route is true, the requested URI and configuration match.
public class Route implements Ordered { private final String id; private final URI uri; private final int order; private final AsyncPredicate<ServerWebExchange> predicate; private final List<GatewayFilter> gatewayFilters; private final Map<String, Object> metadata; }
The member properties of Route are described as follows:
attribute | effect |
---|---|
id | Identifier, different from other routes |
uri | The destination uri that the route points to, that is, the destination where the client request is finally forwarded |
order | It is used for sorting among multiple routes. The smaller the value, the higher the sorting priority and the higher the matching priority |
predicate | Predicate, which indicates the precondition matching the Route, that is, it will be routed to the destination uri only if the corresponding conditions are met |
gatewayFilters | Filters are used to process aspect logic, such as modifying request headers before routing forwarding |
metadata | Metadata that describes the route |
Asyncpredict interface
AsyncPredicate is a member property of Routed, which is used for condition matching.
It implements the functional interface function < T, R >, function < T, R > provided by Java 8, which is used to obtain another type of data according to one type of data. The former is called pre condition and the latter is called post condition.
public interface AsyncPredicate<T> extends Function<T, Publisher<Boolean>> { default AsyncPredicate<T> and(AsyncPredicate<? super T> other) { return new AsyncPredicate.AndAsyncPredicate(this, other); } default AsyncPredicate<T> negate() { return new AsyncPredicate.NegateAsyncPredicate(this); } default AsyncPredicate<T> not(AsyncPredicate<? super T> other) { return new AsyncPredicate.NegateAsyncPredicate(other); } default AsyncPredicate<T> or(AsyncPredicate<? super T> other) { return new AsyncPredicate.OrAsyncPredicate(this, other); } }
AsyncPredicate defines three logical operation methods:
method | explain |
---|---|
and | And operations, that is, two predicates form one, which needs to be met at the same time. |
negate | Reverse operation, that is, reverse the Predicate matching result. |
or | Or operation, that is, two predicates form one, and only one of them needs to be met. |
ServerWebExchange interface
Note to ServerWebExchange: ServerWebExchange is a contract for HTTP request response interaction. Provides access to HTTP requests and responses, and exposes additional server-side processing related properties and features, such as request properties.
In fact, ServerWebExchange is named service network switch, which stores important request response properties, request instances and response instances, which is a bit like the role of Context.
public interface ServerWebExchange { // The KEY of the log prefix attribute is org.springframework.web.server.ServerWebExchange.LOG_ID // It can be understood as attributes.set("org.springframework.web.server.ServerWebExchange.LOG_ID", "specific value of log prefix"); // The function is to splice the prefix value of the KEY when printing the log. The default value is "" String LOG_ID_ATTRIBUTE = ServerWebExchange.class.getName() + ".LOG_ID"; String getLogPrefix(); // Get ServerHttpRequest object ServerHttpRequest getRequest(); // Get ServerHttpResponse object ServerHttpResponse getResponse(); // Returns the request attribute of the current exchange, and the returned result is a variable Map Map<String, Object> getAttributes(); // Get request properties according to KEY @Nullable default <T> T getAttribute(String name) { return (T) getAttributes().get(name); } // Get the request attribute according to the KEY and make a non empty judgment @SuppressWarnings("unchecked") default <T> T getRequiredAttribute(String name) { T value = getAttribute(name); Assert.notNull(value, () -> "Required attribute '" + name + "' is missing"); return value; } // Get the request attribute according to the KEY, and you need to provide a default value @SuppressWarnings("unchecked") default <T> T getAttributeOrDefault(String name, T defaultValue) { return (T) getAttributes().getOrDefault(name, defaultValue); } // Returns the currently requested network session Mono<WebSession> getSession(); // Returns the currently requested authenticated user, if any <T extends Principal> Mono<T> getPrincipal(); // Return the requested form data or an empty Map. This method will return a non empty Map only when the content type is application/x-www-form-urlencoded -- this is usually used for form data submission Mono<MultiValueMap<String, String>> getFormData(); // Return the part data or an empty Map requested by multipart. This method will return a non empty Map only when the content type is multipart / form data -- this is usually used for file upload Mono<MultiValueMap<String, Part>> getMultipartData(); // Returns the context of Spring @Nullable ApplicationContext getApplicationContext(); // These methods are related to the lastModified attribute boolean isNotModified(); boolean checkNotModified(Instant lastModified); boolean checkNotModified(String etag); boolean checkNotModified(@Nullable String etag, Instant lastModified); // URL conversion String transformUrl(String url); // URL translation mapping void addUrlTransformer(Function<String, String> transformer); // Note that the method name is change. This is a method to modify the properties of ServerWebExchange. It returns a Builder instance, which is the internal class of ServerWebExchange default Builder mutate() { return new DefaultServerWebExchangeBuilder(this); } interface Builder { // Overwrite ServerHttpRequest Builder request(Consumer<ServerHttpRequest.Builder> requestBuilderConsumer); Builder request(ServerHttpRequest request); // Override ServerHttpResponse Builder response(ServerHttpResponse response); // Overwrite the currently requested authenticated user Builder principal(Mono<Principal> principalMono); // Build a new ServerWebExchange instance ServerWebExchange build(); } }
GatewayFilter
Gateway Filter is a gateway Filter. Many frameworks have Filter design to realize extensible aspect logic.
GatewayFilter source code:
public interface GatewayFilter extends ShortcutConfigurable { String NAME_KEY = "name"; String VALUE_KEY = "value"; /** * Process the Web request and (optionally) delegate to the next * {@code WebFilter} through the given {@link GatewayFilterChain}. * @param exchange the current server exchange * @param chain provides a way to delegate to the next filter * @return {@code Mono<Void>} to indicate when request processing is complete */ Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain); }
Finally, the filter is called in a chain through the filter chain. Each filter is delegated to the filter chain after processing the pre filter logic, and then the filter chain is delegated to the next filter.
GatewayFilterChain source code:
public interface GatewayFilterChain { /** * Delegate to the next {@code WebFilter} in the chain. * @param exchange the current server exchange * @return {@code Mono<Void>} to indicate when request handling is complete */ Mono<Void> filter(ServerWebExchange exchange); }
RouteLocator
RouteLocator is a route locator used to obtain route objects
public interface RouteLocator { Flux<Route> getRoutes(); }
RouteLocator has three implementation classes:
- RouteDefinitionRouteLocator is a locator based on the route definition
- Cacheingroutelocator cache based route locator
- CompositeRouteLocator routing locator based on combination mode
RouteDefinitionLocator interface
RouteDefinitionLocator is the top-level interface of the route definition locator. Its main function is to read the route configuration information (org.springframework.cloud.gateway.route.RouteDefinition). It has five different implementation classes, as shown in figure
org.springframework.cloud.gateway.route.RouteDefinitionLocator, the route definition locator interface, has only one method, which is used to obtain the route definition list.
public interface RouteDefinitionLocator { Flux<RouteDefinition> getRouteDefinitions(); }
From the class diagram of RouteDefinitionLocator, you can see that the interface has multiple implementation classes:
- PropertiesRouteDefinitionLocator: property based configuration
- DiscoveryClientRouteDefinitionLocator: Based on service discovery
- CompositeRouteDefinitionLocator: combination method
- Cacheingroutedefinitionlocator: cache mode
- There is also an interface RouteDefinitionRepository, which inherits from RouteDefinitionLocator and is used for operations on route definitions (saving and deleting route definitions). It has only one default implementation class, InMemoryRouteDefinitionRepository
RouteDefinition class
As the name suggests, this component is used to define Route information, which will eventually be parsed into Route by RouteLocator, and its properties are similar to those of Route class.
@Validated public class RouteDefinition { private String id; @NotEmpty @Valid private List<PredicateDefinition> predicates = new ArrayList(); @Valid private List<FilterDefinition> filters = new ArrayList(); @NotNull private URI uri; private Map<String, Object> metadata = new HashMap(); private int order = 0; }
Initialize loading process
1. Route construction method
Spring provides two ways: externalizing configuration and programming.
Externalized configuration:
spring: cloud: gateway: enabled: true routes: - id: app-service001 # Route unique ID uri: http://localhost:9000 # destination URI, predicates: # Assertion. If true, the match succeeds - Path=/app1/** # Configure the rule Path. If the request starts with app1, it will be forwarded to the target URL filters: - AddRequestHeader=X-Request-Foo, Bar # A Filter is defined. When all requests are forwarded to downstream services, the request header X-Request-Foo:Bar will be added, which is produced by AddRequestHeaderGatewayFilterFactory.
Programming mode:
@Bean public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) { return builder.routes() .route(r -> r.path("/app1/**") .filters(f -> f.filter(new RequestLogGatewayFilter())) .uri("http://localhost:9000") ) .build(); }
2. Load configuration
Based on the automatic assembly function of Spring Boot, the automatic assembly class of Gateway module is GatewayAutoConfiguration, and the corresponding configuration class is GatewayProperties.
You can see that many Bean objects need to be used are injected into GatewayAutoConfiguration.
After configuring the route in yml, it will be resolved into a RouteDefinition object set when loaded. Each RouteDefinition contains Id, uri, predictions, filters, etc.
3. Load PropertiesRouteDefinitionLocator
PropertiesRouteDefinitionLocator is RouteDefinitionLocator, which is mainly used to obtain RouteDefinition (route definition information),
You can see that it is created directly using GatewayProperties,
@Bean @ConditionalOnMissingBean public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(GatewayProperties properties) { return new PropertiesRouteDefinitionLocator(properties); }
Our routing information is stored in the PropertiesRouteDefinitionLocator Bean object.
4. Load RouteDefinitionRouteLocator
RouteDefinitionRouteLocator will also be loaded in the GatewayAutoConfiguration class. Be careful not to confuse it with the RouteDefinitionLocator above. The name is very similar to:
- RouteDefinitionLocator: load the route as RouteDefinition through configuration, JAVA code and service discovery.
- RouteDefinitionRouteLocator: used to convert RouteDefinition to Route.
@Bean public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties, List<GatewayFilterFactory> gatewayFilters, List<RoutePredicateFactory> predicates, RouteDefinitionLocator routeDefinitionLocator, ConfigurationService configurationService) { return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, gatewayFilters, properties, configurationService); }
You can see that the GatewayProperties, GatewayFilterFactory, RoutePredicateFactory, RouteDefinitionLocator and ConfigurationService are passed in using the RouteDefinitionRouteLocator constructor. Yes, there are 28 gateway filters and 13 assertion factories.
Its constructor initializes the relevant properties,
public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator, List<RoutePredicateFactory> predicates, List<GatewayFilterFactory> gatewayFilterFactories, GatewayProperties gatewayProperties, ConfigurationService configurationService) { // Set RouteDefinitionLocator this.routeDefinitionLocator = routeDefinitionLocator; // Setting ConfigurationService this.configurationService = configurationService; // Initialize predictions, put all routepredictefactories into one Map, and print the "loaded routepredictefactory + prefix log" this.initFactories(predicates); // Initialize the GatewayFilter and put all gatewayfilters into one Map gatewayFilterFactories.forEach((factory) -> { GatewayFilterFactory var10000 = (GatewayFilterFactory)this.gatewayFilterFactories.put(factory.name(), factory); }); // Set GatewayProperties this.gatewayProperties = gatewayProperties; }
Finally, the Route locator is initialized and injected into the Spring IOC, which maintains the Route information, filter, assertion factory and other information.
5. Load HandlerMapping and WebHandler
Before file In, we analyzed the execution process of the gateway,
The client sends a request to the Spring Cloud Gateway. The Gateway Handler Mapping determines the route matching the request and sends it to the Gateway Web Handler. The handler also sends the request to our actual service through the specified filter, executes the business logic, and then returns.
Therefore, during Gateway initialization, HandlerMapping and WebHandler will be loaded. This involves the relevant knowledge of Web flux, which will be described in detail later.
@Bean public FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) { return new FilteringWebHandler(globalFilters); } @Bean public RoutePredicateHandlerMapping routePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties, Environment environment) { return new RoutePredicateHandlerMapping(webHandler, routeLocator, globalCorsProperties, environment); }
5. Start service
After all components are initialized, the service is started and completed. The web program listens to the port, receives external requests, passes through the core controller, processing mapper, web processor and filter, reaches the target address, returns all the way, and the whole process ends.
Reference documents
https://www.iocoder.cn/Spring-Cloud-Gateway/ouwenxue/intro/
https://www.cnblogs.com/fdzang/p/11812348.html