5. handle方法详解-handler获取
主要分享handle方法内部逻辑中的mapping.getHandler(exchange)方法的实现原理,得出gateway使用的是RoutePredicateHandlerMapping的实现的结论。
文章目录
- 1.概览
- 2. handle方法回顾
- 3. HandlerMappings继承关系
- 4. getHandlerInternal
- 4.1 RequestMappingInfoHandlerMapping.getHandlerInternal
- 4.2 AbstractUrlHandlerMapping.getHandlerInternal
- 4.3 RouterFunctionMapping.getHandlerInternal
- 4.4 RoutePredicateHandlerMapping.getHandlerInternal
- 5. 总结
1.概览
本节是gateway入口DispatcherHandler.handle()方法原理分享的第二节,本节主要分享handle方法内部逻辑中的mapping.getHandler(exchange)方法的实现原理,本节较长,希望大家耐心看完。
2. handle方法回顾
为了方便分享,我还是把handle方法的源码展示如下:
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
if (this.handlerMappings == null) {
return createNotFoundError();
}
return Flux.fromIterable(this.handlerMappings)
.concatMap(mapping -> mapping.getHandler(exchange))//本节分享这个方法实现原理
.next()
.switchIfEmpty(createNotFoundError())
.flatMap(handler -> invokeHandler(exchange, handler))
.flatMap(result -> handleResult(exchange, result));
}
上一节我分享了handlerMappings是如何获取的,本节分享mapping.getHandler(exchange)方法的实现细节,探索下handler是如何获取的。
3. HandlerMappings继承关系
为了便于理解,我准备了一张HandlerMapping接口的类继承图,6个handlerMappings bean被标记成了绿色(如果对这6个bean的来源有疑问,请参考上一节)。
4. getHandlerInternal
Flux.fromIterable(this.handlerMappings)会迭代handlerMappings list,迭代出的每个mapping会调用mapping的getHandler(exchange)方法,getHandler(exchange)方法的定义在HandlerMapping接口里,它的实现类只有一个,是AbstractHandlerMapping。getHandler(exchange)方法的源码如下:
@Override
public Mono<Object> getHandler(ServerWebExchange exchange) {
return getHandlerInternal(exchange).map(handler -> {
if (logger.isDebugEnabled()) {
logger.debug(exchange.getLogPrefix() + "Mapped to " + handler);
}
ServerHttpRequest request = exchange.getRequest();
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(exchange) : null);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, exchange);
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
if (!this.corsProcessor.process(config, exchange) || CorsUtils.isPreFlightRequest(request)) {
return REQUEST_HANDLED_HANDLER;
}
}
return handler;
});
}
getHandler(exchange)首先调用getHandlerInternal(exchange)方法获取handler,getHandlerInternal方法分散在不同类中,根据handlerMappings继承关系图,我画出了getHandlerInternal(exchange)方法的调用图,如下所示,红色的箭头是mappings方法调用的getHandlerInternal方法所处的位置。
我们逐个看一下六个mapping bean调用的getHandlerInternal方法的源码,看一下内部是如何执行的,mapping.getHandler()到底使用的是哪个HandlerMapping。
4.1 RequestMappingInfoHandlerMapping.getHandlerInternal
首先看RequestMappingInfoHandlerMapping,它调用了父类也就是AbstractHandlerMethodMapping的getHandlerInternal方法,代码如下:
@Override
public Mono<HandlerMethod> getHandlerInternal(ServerWebExchange exchange) {
exchange.getAttributes().remove(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
return super.getHandlerInternal(exchange) 此行
.doOnTerminate(() -> ProducesRequestCondition.clearMediaTypesAttribute(exchange));
}
4.1.1 AbstractHandlerMethodMapping.getHandlerInternal
AbstractHandlerMethodMapping.getHandlerInternal方法的源代码如下:
@Override
public Mono<HandlerMethod> getHandlerInternal(ServerWebExchange exchange) {
this.mappingRegistry.acquireReadLock();
try {
HandlerMethod handlerMethod;
try {
handlerMethod = lookupHandlerMethod(exchange);//此行
}
catch (Exception ex) {
return Mono.error(ex);
}
if (handlerMethod != null) {
handlerMethod = handlerMethod.createWithResolvedBean();//此行
}
return Mono.justOrEmpty(handlerMethod);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
这段代码有两处比较关键,一处是lookupHandlerMethod(exchange), 找到一个handlerMethod, 另一处调用了handlerMethod的createWithResolvedBean()方法,返回了一个新的handlerMethod。先来看一下lookupHandlerMethod(exchange)的实现细节,它的源代码如下:
protected HandlerMethod lookupHandlerMethod(ServerWebExchange exchange) throws Exception {
List<Match> matches = new ArrayList<>();
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, exchange); //此行
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(exchange));
matches.sort(comparator);
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (logger.isTraceEnabled()) {
logger.trace(exchange.getLogPrefix() + matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(exchange.getRequest())) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
RequestPath path = exchange.getRequest().getPath();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + path + "': {" + m1 + ", " + m2 + "}");
}
}
handleMatch(bestMatch.mapping, bestMatch.handlerMethod, exchange);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), exchange);
}
}
它首先调用addMatchingMappings方法,在matches里放入Match,并根据matches是否为空做进一步处理,如果不为空则返回handlerMethod,如果为空则调用handleNoMatch方法,handleNoMatch方法返回null,代表没有找打handler。
protected HandlerMethod handleNoMatch(Set<T> mappings, ServerWebExchange exchange) throws Exception {
return null;
}
在来看addMatchingMappings方法,它的第一个参数是this.mappingRegistry.getMappings().keySet(),那mappingRegistry是在哪初始化的呢,
初始化mappingRegistry有两处,代码如下所示:
public void registerMapping(T mapping, Object handler, Method method) {
if (logger.isTraceEnabled()) {
logger.trace("Register \"" + mapping + "\" to " + method.toGenericString());
}
this.mappingRegistry.register(mapping, handler, method);
}
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
这两处都是为了子类注册handler用的,我们逐个看下子类是怎样注册的。
4.1.1.1 子类RequestMappingInfoHandlerMapping的registerMapping
子类RequestMappingInfoHandlerMapping 调用了父类的方法,也就是AbstractHandlerMethodMapping的registerMapping
@Override
public void registerMapping(RequestMappingInfo mapping, Object handler, Method method) {
super.registerMapping(mapping, handler, method);
updateConsumesCondition(mapping, method);
}
4.1.1.2 子类RequestMappingHandlerMapping的registerMapping
子类RequestMappingHandlerMapping 也调用了父类的方法,也就是RequestMappingInfoHandlerMapping的registerMapping
@Override
public void registerMapping(RequestMappingInfo mapping, Object handler, Method method) {
super.registerMapping(mapping, handler, method);
updateConsumesCondition(mapping, method);
}
4.1.1.3 子类ControllerEndpointHandlerMapping的registerMapping
子类ControllerEndpointHandlerMapping在registerHandlerMethod方法里调用了父类RequestMappingHandlerMapping的registerMapping方法。
@Override
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
ExposableControllerEndpoint endpoint = this.handlers.get(handler);
mapping = withEndpointMappedPatterns(endpoint, mapping);
super.registerHandlerMethod(handler, method, mapping);
}
4.1.1.4 子类AbstractWebMvcEndpointHandlerMapping的registerMapping
子类AbstractWebMvcEndpointHandlerMapping通过initHandlerMethods方法注册registerMapping
@Override
protected void initHandlerMethods() {
for (ExposableWebEndpoint endpoint : this.endpoints) {
for (WebOperation operation : endpoint.getOperations()) {
registerMappingForOperation(endpoint, operation);//此行
}
}
if (this.shouldRegisterLinksMapping) {
registerLinksMapping();
}
}
private void registerMappingForOperation(ExposableWebEndpoint endpoint, WebOperation operation) {
WebOperationRequestPredicate predicate = operation.getRequestPredicate();
String path = predicate.getPath();
String matchAllRemainingPathSegmentsVariable = predicate.getMatchAllRemainingPathSegmentsVariable();
if (matchAllRemainingPathSegmentsVariable != null) {
path = path.replace("{*" + matchAllRemainingPathSegmentsVariable + "}", "**");
}
ServletWebOperation servletWebOperation = wrapServletWebOperation(endpoint, operation,
new ServletWebOperationAdapter(operation));
registerMapping(createRequestMappingInfo(predicate, path), new OperationHandler(servletWebOperation),
this.handleMethod);//此行
}
private void registerLinksMapping() {
PatternsRequestCondition patterns = patternsRequestConditionForPattern("");
RequestMethodsRequestCondition methods = new RequestMethodsRequestCondition(RequestMethod.GET);
ProducesRequestCondition produces = new ProducesRequestCondition(this.endpointMediaTypes.getProduced()
.toArray(StringUtils.toStringArray(this.endpointMediaTypes.getProduced())));
RequestMappingInfo mapping = new RequestMappingInfo(patterns, methods, null, null, null, produces, null);
LinksHandler linksHandler = getLinksHandler();
registerMapping(mapping, linksHandler, ReflectionUtils.findMethod(linksHandler.getClass(), "links",
HttpServletRequest.class, HttpServletResponse.class));//此行
}
4.1.1.5 子类AbstractWebFluxEndpointHandlerMapping的registerMapping
子类AbstractWebFluxEndpointHandlerMapping注册registerMapping的方式与AbstractWebMvcEndpointHandlerMapping大同小异
@Override
protected void initHandlerMethods() {
for (ExposableWebEndpoint endpoint : this.endpoints) {
for (WebOperation operation : endpoint.getOperations()) {
registerMappingForOperation(endpoint, operation);
}
}
if (this.shouldRegisterLinksMapping) {
registerLinksMapping();
}
}
private void registerMappingForOperation(ExposableWebEndpoint endpoint, WebOperation operation) {
ReactiveWebOperation reactiveWebOperation = wrapReactiveWebOperation(endpoint, operation,
new ReactiveWebOperationAdapter(operation));
if (operation.getType() == OperationType.WRITE) {
registerMapping(createRequestMappingInfo(operation), new WriteOperationHandler((reactiveWebOperation)),
this.handleWriteMethod);
}
else {
registerMapping(createRequestMappingInfo(operation), new ReadOperationHandler((reactiveWebOperation)),
this.handleReadMethod);
}
}
private void registerLinksMapping() {
PatternsRequestCondition patterns = new PatternsRequestCondition(
pathPatternParser.parse(this.endpointMapping.getPath()));
RequestMethodsRequestCondition methods = new RequestMethodsRequestCondition(RequestMethod.GET);
ProducesRequestCondition produces = new ProducesRequestCondition(
StringUtils.toStringArray(this.endpointMediaTypes.getProduced()));
RequestMappingInfo mapping = new RequestMappingInfo(patterns, methods, null, null, null, produces, null);
LinksHandler linksHandler = getLinksHandler();
registerMapping(mapping, linksHandler,
ReflectionUtils.findMethod(linksHandler.getClass(), "links", ServerWebExchange.class));
}
4.1.2 registerMapping方法触发时机
这些类都继承了AbstractHandlerMethodMapping,AbstractHandlerMethodMapping实现了InitializingBean类,在afterPropertiesSet方法中触发了initHandlerMethods()方法的调用
@Override
public void afterPropertiesSet() {
initHandlerMethods();//此行
// Total includes detected mappings + explicit registrations via registerMapping..
int total = this.getHandlerMethods().size();
if ((logger.isTraceEnabled() && total == 0) || (logger.isDebugEnabled() && total > 0) ) {
logger.debug(total + " mappings in " + formatMappingName());
}
}
initHandlerMethods()方法也在AbstractHandlerMethodMapping类中,被所有的子类继承,它的源代码如下:
protected void initHandlerMethods() {
String[] beanNames = obtainApplicationContext().getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isTraceEnabled()) {
logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
}
}
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);//此行
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
在这个方法中调用了detectHandlerMethods(beanName)方法,这个方法也在AbstractHandlerMethodMapping类中,被所有的子类继承,源代码如下:
protected void detectHandlerMethods(final Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
final Class<?> userType = ClassUtils.getUserClass(handlerType);
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> getMappingForMethod(method, userType));
if (logger.isTraceEnabled()) {
logger.trace(formatMappings(userType, methods));
}
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping); //此行
});
}
}
这个方法触发了registerHandlerMethod方法的调用,最终调用到registerMapping方法。
4.1.3 isHandler(beanType)
initHandlerMethods方法的第16行有一个判断:isHandler(beanType),判断bean是否是Handler,如果是Handler则执行detectHandlerMethods方法。
isHandler(beanType)方法的定义在AbstractHandlerMethodMapping中,它的实现类共有两个,一个在AbstractWebFluxEndpointHandlerMapping中,一个在RequestMappingHandlerMapping中,如下图所示。
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);//此行
}
AbstractWebFluxEndpointHandlerMapping的isHandler方法直接返回的false,由类继承关系图可知,类WebFluxEndpointHandlerMapping不是handler。
@Override
protected boolean isHandler(Class<?> beanType) {
return false;
}
RequestMappingHandlerMapping的isHandler方法判断bean上是否有Controller或者RequestMapping注解,我们用gateway,显然是不会标注这两个注解的,根据类继承关系图,RequestMappingHandlerMapping和其子类ControllerEndpointHandlerMapping也不是handler(仅在gateway的情况下,区别于webmvc的场景)。
@Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
4.2 AbstractUrlHandlerMapping.getHandlerInternal
AbstractUrlHandlerMapping.getHandlerInternal首先获取lookupPath,根据lookupPath获取handler,代码如下所示:
@Override
public Mono<Object> getHandlerInternal(ServerWebExchange exchange) {
PathContainer lookupPath = exchange.getRequest().getPath().pathWithinApplication();
Object handler;
try {
handler = lookupHandler(lookupPath, exchange);//此行
}
catch (Exception ex) {
return Mono.error(ex);
}
return Mono.justOrEmpty(handler);
}
lookupHandler方法的源代码如下所示,根据handlerMap获取PathPattern list,根据list做相关处理,如果list为空返回null,表示未找到handler,
如果不为空,则找到handler。
@Nullable
protected Object lookupHandler(PathContainer lookupPath, ServerWebExchange exchange) throws Exception {
List<PathPattern> matches = this.handlerMap.keySet().stream()
.filter(key -> key.matches(lookupPath))
.collect(Collectors.toList());
if (matches.isEmpty()) {
return null;
}
if (matches.size() > 1) {
matches.sort(PathPattern.SPECIFICITY_COMPARATOR);
if (logger.isTraceEnabled()) {
logger.debug(exchange.getLogPrefix() + "Matching patterns " + matches);
}
}
PathPattern pattern = matches.get(0);
PathContainer pathWithinMapping = pattern.extractPathWithinPattern(lookupPath);
return handleMatch(this.handlerMap.get(pattern), pattern, pathWithinMapping, exchange);
}
4.2.1 handlerMap加载
handlerMap的初始化在SimpleUrlHandlerMapping类中,由类的继承关系图可知,SimpleUrlHandlerMapping继承自ApplicationObjectSupport,ApplicationObjectSupport实现自ApplicationContextAware,在ApplicationObjectSupport中触发了initApplicationContext的加载
@Override
public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
if (context == null && !isContextRequired()) {
// Reset internal context state.
this.applicationContext = null;
this.messageSourceAccessor = null;
}
else if (this.applicationContext == null) {
// Initialize with passed-in context.
if (!requiredContextClass().isInstance(context)) {
throw new ApplicationContextException(
"Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
}
this.applicationContext = context;
this.messageSourceAccessor = new MessageSourceAccessor(context);
initApplicationContext(context);//此行
}
else {
// Ignore reinitialization if same context passed in.
if (this.applicationContext != context) {
throw new ApplicationContextException(
"Cannot reinitialize with different application context: current one is [" +
this.applicationContext + "], passed-in one is [" + context + "]");
}
}
}
@Override
public void initApplicationContext() throws BeansException {
super.initApplicationContext();
registerHandlers(this.urlMap);
}
4.2.2 urlMap初始化
不同的场景,有不同的初始化urlMap的方式,WebFlux是在WebFluxConfigurationSupport类中,WebMvc是在WebMvcConfigurationSupport类中,初始化逻辑大同小异,先看下WebFluxConfigurationSupport中是如何初始化的,初始化的bean代码如下:
@Bean
public HandlerMapping resourceHandlerMapping(ResourceUrlProvider resourceUrlProvider) {
ResourceLoader resourceLoader = this.applicationContext;
if (resourceLoader == null) {
resourceLoader = new DefaultResourceLoader();
}
ResourceHandlerRegistry registry = new ResourceHandlerRegistry(resourceLoader);
registry.setResourceUrlProvider(resourceUrlProvider);
addResourceHandlers(registry);
//此行获取的就是SimpleURLHandlerMapping
AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
if (handlerMapping != null) {
PathMatchConfigurer configurer = getPathMatchConfigurer();
Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
Boolean useCaseSensitiveMatch = configurer.isUseCaseSensitiveMatch();
if (useTrailingSlashMatch != null) {
handlerMapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
}
if (useCaseSensitiveMatch != null) {
handlerMapping.setUseCaseSensitiveMatch(useCaseSensitiveMatch);
}
}
else {
handlerMapping = new EmptyHandlerMapping();
}
return handlerMapping;
}
WebMvcConfigurationSupport类中是这样初始化的:
@Bean
@Nullable
public HandlerMapping viewControllerHandlerMapping(
@Qualifier("mvcPathMatcher") PathMatcher pathMatcher,
@Qualifier("mvcUrlPathHelper") UrlPathHelper urlPathHelper,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
ViewControllerRegistry registry = new ViewControllerRegistry(this.applicationContext);
addViewControllers(registry);
AbstractHandlerMapping handlerMapping = registry.buildHandlerMapping();//
if (handlerMapping == null) {
return null;
}
handlerMapping.setPathMatcher(pathMatcher);
handlerMapping.setUrlPathHelper(urlPathHelper);
handlerMapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
handlerMapping.setCorsConfigurations(getCorsConfigurations());
return handlerMapping;
}
我们在使用gateway的时候,显然不会配置url和handler的映射关系,所以SimpleUrlHandlerMapping也不是DispatcherHandler.handle()方法中使用的handler。
4.3 RouterFunctionMapping.getHandlerInternal
RouterFunctionMapping.getHandlerInternal根据routerFunction是否为空做下一步处理,当routerFunction为空时返回空的Mono,不为空时调用routerFunction的route方法处理请求,代码如下所示:
@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
if (this.routerFunction != null) {
ServerRequest request = ServerRequest.create(exchange, this.messageReaders);
return this.routerFunction.route(request)
.doOnNext(handler -> setAttributes(exchange.getAttributes(), request, handler));
}
else {
return Mono.empty();
}
}
4.3.1 routerFunction的初始化
由HandlerMapping继承关系图可知,RouterFunctionMapping实现了InitializingBean,routerFunction的初始化在RouterFunctionMapping覆写的afterPropertiesSet方法中,它调用了initRouterFunctions()方法。
@Override
public void afterPropertiesSet() throws Exception {
if (CollectionUtils.isEmpty(this.messageReaders)) {
ServerCodecConfigurer codecConfigurer = ServerCodecConfigurer.create();
this.messageReaders = codecConfigurer.getReaders();
}
if (this.routerFunction == null) {
initRouterFunctions();
}
}
initRouterFunctions方法如下所示,从routerFunctions()方法获取RouterFunction list
protected void initRouterFunctions() {
List<RouterFunction<?>> routerFunctions = routerFunctions();
this.routerFunction = routerFunctions.stream().reduce(RouterFunction::andOther).orElse(null);
logRouterFunctions(routerFunctions);
}
routerFunctions方法获取所有RouterFunction类型的bean,并组织成List返回,代码如下所示:
private List<RouterFunction<?>> routerFunctions() {
List<RouterFunction<?>> functions = obtainApplicationContext()
.getBeanProvider(RouterFunction.class)
.orderedStream()
.map(router -> (RouterFunction<?>)router)
.collect(Collectors.toList());
return (!CollectionUtils.isEmpty(functions) ? functions : Collections.emptyList());
}
4.3.2 RouterFunction构造
RouterFunction是Spring Framework 5中的概念,RouterFunction以如下所示的代码的方式构建。
@Bean
public RouterFunction<ServerResponse> initRouterFunction(){
return RouterFunctions.route()
.GET("/hello/**",serverRequest -> {
System.out.println("path:"+serverRequest.exchange().getRequest().getPath().pathWithinApplication().value());
return ServerResponse.ok().bodyValue("hello world");
})
.filter((serverRequest, handlerFunction) -> {
System.out.println("hello world test");
return handlerFunction.handle(serverRequest);
})
.build();
}
我们gateway里没有这种方式。
4.4 RoutePredicateHandlerMapping.getHandlerInternal
RoutePredicateHandlerMapping.getHandlerInternal首先调用lookupRoute函数,接下来通过flatMap把Route转换成了Mono,也就是return Mono.just(webHandler),这里的webHandler是FilteringWebHandler,源代码如下:
private final FilteringWebHandler webHandler;
@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
// don't handle requests on management port if set and different than server port
if (this.managementPortType == DIFFERENT && this.managementPort != null
&& exchange.getRequest().getURI().getPort() == this.managementPort) {
return Mono.empty();
}
exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());
return lookupRoute(exchange)
// .log("route-predicate-handler-mapping", Level.FINER) //name this
.flatMap((Function<Route, Mono<?>>) r -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
if (logger.isDebugEnabled()) {
logger.debug(
"Mapping [" + getExchangeDesc(exchange) + "] to " + r);
}
exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
return Mono.just(webHandler);
}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
if (logger.isTraceEnabled()) {
logger.trace("No RouteDefinition found for ["
+ getExchangeDesc(exchange) + "]");
}
})));
}
4.4.1 lookupRoute(exchange)
lookupRoute从routeLocator中迭代route,并返回第一个满足断言的route,源代码如下所示:
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
return this.routeLocator.getRoutes()
// individually filter routes so that filterWhen error delaying is not a
// problem
.concatMap(route -> Mono.just(route).filterWhen(r -> {
// add the current route we are testing
exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
return r.getPredicate().apply(exchange);
})
// instead of immediately stopping main flux due to error, log and
// swallow it
.doOnError(e -> logger.error(
"Error applying predicate for route: " + route.getId(),
e))
.onErrorResume(e -> Mono.empty()))
// .defaultIfEmpty() put a static Route not found
// or .switchIfEmpty()
// .switchIfEmpty(Mono.<Route>empty().log("noroute"))
.next()
// TODO: error handling
.map(route -> {
if (logger.isDebugEnabled()) {
logger.debug("Route matched: " + route.getId());
}
validateRoute(route, exchange);
return route;
});
/*
* TODO: trace logging if (logger.isTraceEnabled()) {
* logger.trace("RouteDefinition did not match: " + routeDefinition.getId()); }
*/
}
4.4.2 routeLocator初始化
routeLocator在初始化RoutePredicateHandlerMapping构造函数初始化,代码如下:
public RoutePredicateHandlerMapping(FilteringWebHandler webHandler,
RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties,
Environment environment) {
this.webHandler = webHandler;
this.routeLocator = routeLocator;
this.managementPort = getPortProperty(environment, "management.server.");
this.managementPortType = getManagementPortType(environment);
setOrder(1);
setCorsConfigurations(globalCorsProperties.getCorsConfigurations());
}
构造函数在GateAutoConfiguration自动装配类中,作为bean初始化
@Bean
public RoutePredicateHandlerMapping routePredicateHandlerMapping(
FilteringWebHandler webHandler, RouteLocator routeLocator,
GlobalCorsProperties globalCorsProperties, Environment environment) {
return new RoutePredicateHandlerMapping(webHandler, routeLocator,
globalCorsProperties, environment);
}
初始化时第二个参数RouteLocator的初始化也在GatewayAutoConfiguration中,注意@primary注解,这是gateway使用的RouteLocator。
@Bean
@Primary
@ConditionalOnMissingBean(name = "cachedCompositeRouteLocator")
// TODO: property to disable composite?
public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
return new CachingRouteLocator(
new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
}
它上的参数List是RouteDefinitionRouteLocator类的实例。
@Bean
public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
List<GatewayFilterFactory> gatewayFilters,
List<RoutePredicateFactory> predicates,
RouteDefinitionLocator routeDefinitionLocator,
ConfigurationService configurationService) {
return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates,
gatewayFilters, properties, configurationService);
}
这个类需要五个参数
1. GatewayProperties读取的是前缀为“spring.cloud.gateway”的gateway的yaml配置文件。
2. List GatewayFilterFactory的bean初始化在GatewayAutoConfiguration类中。
3. List predicates的初始化也在GatewayAutoConfiguration类中。
4. RouteDefinitionLocator 读取的是接口路由配置文件。
5. ConfigurationService 主要一些系统级别的信息,beanFactory、Conversion、Validator等,它的bean定义如下:
@Bean
public ConfigurationService gatewayConfigurationService(BeanFactory beanFactory,
@Qualifier("webFluxConversionService") ObjectProvider<ConversionService> conversionService,
ObjectProvider<Validator> validator) {
return new ConfigurationService(beanFactory, conversionService, validator);
}
由此可知,gateway使用的handlerMapping为RoutePredicateHandlerMapping。
5. 总结
本篇文章通过分析源码的形式,分析了mapping.getHandler(exchange)的实现原理。
得出getHandler(exchange)内部方法getHandlerInternal(exchange)调用的是RoutePredicateHandlerMapping的实现。
更多推荐
所有评论(0)