通过spring-boot-autoconfigure中的spring.factories文件,通过Spring Boot自动初始化下列类:HttpHandlerAutoConfiguration
、ReactiveWebServerFactoryAutoConfiguration、WebFluxAutoConfiguration
、ErrorWebFluxAutoConfiguration、ClientHttpConnectorAutoConfiguration、WebClientAutoConfiguration。
通过WebFluxConfig完成需要类的初始化,是通过EnableWebFluxConfiguration类完成,该类继承了WebFluxConfigurationSupport。
完成了将DispatcherHandler 和ListMono.defer订阅Reactor服务
。完成操作后通过HttpWebHandlerAdapter
完成将HttpHandler
转为WebHandler
可执行的类。
@Bean
public DispatcherHandler webHandler() {
return new DispatcherHandler();
}
DispatcherHandler主要执行方法:
HandlerMapping
找到和ServerWebExchange 对应的HandlerMapping并去除Handler
。HandlerAdapter
找到对应的HandlerAdapter,由具体HandlerAdapter执行当前请求。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));
}
private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
if (this.handlerAdapters != null) {
for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
if (handlerAdapter.supports(handler)) {
return handlerAdapter.handle(exchange, handler);
}
}
}
return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}
private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
return getResultHandler(result).handleResult(exchange, result)
.checkpoint("Handler " + result.getHandler() + " [DispatcherHandler]")
.onErrorResume(ex ->
result.applyExceptionHandler(ex).flatMap(exResult -> {
String text = "Exception handler " + exResult.getHandler() +
", error=\"" + ex.getMessage() + "\" [DispatcherHandler]";
return getResultHandler(exResult).handleResult(exchange, exResult).checkpoint(text);
}));
}
从isHandler方法中可以知道这里只自动加载Controller
和RequestMapping
注解的类。
从createRequestMappingInfo方法中可以知道只加载方法上有RequestMapping
注解方法。
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping(
@Qualifier("webFluxContentTypeResolver") RequestedContentTypeResolver contentTypeResolver) {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
mapping.setContentTypeResolver(contentTypeResolver);
mapping.setCorsConfigurations(getCorsConfigurations());
PathMatchConfigurer configurer = getPathMatchConfigurer();
Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
if (useTrailingSlashMatch != null) {
mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
}
Boolean useCaseSensitiveMatch = configurer.isUseCaseSensitiveMatch();
if (useCaseSensitiveMatch != null) {
mapping.setUseCaseSensitiveMatch(useCaseSensitiveMatch);
}
Map<String, Predicate<Class<?>>> pathPrefixes = configurer.getPathPrefixes();
if (pathPrefixes != null) {
mapping.setPathPrefixes(pathPrefixes);
}
return mapping;
}
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
从routerFunctions方法中可以知道该类只加载Bean实现了RouterFunction
接口的类。
@Bean
public RouterFunctionMapping routerFunctionMapping(ServerCodecConfigurer serverCodecConfigurer) {
RouterFunctionMapping mapping = createRouterFunctionMapping();
mapping.setOrder(-1); // go before RequestMappingHandlerMapping
mapping.setMessageReaders(serverCodecConfigurer.getReaders());
mapping.setCorsConfigurations(getCorsConfigurations());
return mapping;
}
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());
}
@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);
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;
}
@Bean
public ResourceUrlProvider resourceUrlProvider() {
return new ResourceUrlProvider();
}
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
@Qualifier("webFluxAdapterRegistry") ReactiveAdapterRegistry reactiveAdapterRegistry,
ServerCodecConfigurer serverCodecConfigurer,
@Qualifier("webFluxConversionService") FormattingConversionService conversionService,
@Qualifier("webFluxValidator") Validator validator) {
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
adapter.setMessageReaders(serverCodecConfigurer.getReaders());
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));
adapter.setReactiveAdapterRegistry(reactiveAdapterRegistry);
ArgumentResolverConfigurer configurer = new ArgumentResolverConfigurer();
configureArgumentResolvers(configurer);
adapter.setArgumentResolverConfigurer(configurer);
return adapter;
}
@Bean
public HandlerFunctionAdapter handlerFunctionAdapter() {
return new HandlerFunctionAdapter();
}
@Bean
public SimpleHandlerAdapter simpleHandlerAdapter() {
return new SimpleHandlerAdapter();
}
@Bean
public ResponseEntityResultHandler responseEntityResultHandler(
@Qualifier("webFluxAdapterRegistry") ReactiveAdapterRegistry reactiveAdapterRegistry,
ServerCodecConfigurer serverCodecConfigurer,
@Qualifier("webFluxContentTypeResolver") RequestedContentTypeResolver contentTypeResolver) {
return new ResponseEntityResultHandler(serverCodecConfigurer.getWriters(),
contentTypeResolver, reactiveAdapterRegistry);
}
@Bean
public ResponseBodyResultHandler responseBodyResultHandler(
@Qualifier("webFluxAdapterRegistry") ReactiveAdapterRegistry reactiveAdapterRegistry,
ServerCodecConfigurer serverCodecConfigurer,
@Qualifier("webFluxContentTypeResolver") RequestedContentTypeResolver contentTypeResolver) {
return new ResponseBodyResultHandler(serverCodecConfigurer.getWriters(),
contentTypeResolver, reactiveAdapterRegistry);
}
@Bean
public ViewResolutionResultHandler viewResolutionResultHandler(
@Qualifier("webFluxAdapterRegistry") ReactiveAdapterRegistry reactiveAdapterRegistry,
@Qualifier("webFluxContentTypeResolver") RequestedContentTypeResolver contentTypeResolver) {
ViewResolverRegistry registry = getViewResolverRegistry();
List<ViewResolver> resolvers = registry.getViewResolvers();
ViewResolutionResultHandler handler = new ViewResolutionResultHandler(
resolvers, contentTypeResolver, reactiveAdapterRegistry);
handler.setDefaultViews(registry.getDefaultViews());
handler.setOrder(registry.getOrder());
return handler;
}
@Bean
public ServerResponseResultHandler serverResponseResultHandler(ServerCodecConfigurer serverCodecConfigurer) {
List<ViewResolver> resolvers = getViewResolverRegistry().getViewResolvers();
ServerResponseResultHandler handler = new ServerResponseResultHandler();
handler.setMessageWriters(serverCodecConfigurer.getWriters());
handler.setViewResolvers(resolvers);
return handler;
}
继承WebFluxConfigurationSupport
主要执行方法
Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response);
继承了WebHandlerDecorator,,实现了HttpHandler
1.通过createExchange方法将ServerHttpRequest和ServerHttpResponse转换为ServerWebExchange供应WebHandler使用。
2.通过代理执行WebHandler的方法。
3.处理异常请求
4.成功返回。
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
if (this.forwardedHeaderTransformer != null) {
try {
request = this.forwardedHeaderTransformer.apply(request);
} catch (Throwable var4) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to apply forwarded headers to " + this.formatRequest(request), var4);
}
response.setStatusCode(HttpStatus.BAD_REQUEST);
return response.setComplete();
}
}
ServerWebExchange exchange = this.createExchange(request, response);
LogFormatUtils.traceDebug(logger, (traceOn) -> {
return exchange.getLogPrefix() + this.formatRequest(exchange.getRequest()) + (traceOn ? ", headers=" + this.formatHeaders(exchange.getRequest().getHeaders()) : "");
});
Mono var10000 = this.getDelegate().handle(exchange).doOnSuccess((aVoid) -> {
this.logResponse(exchange);
}).onErrorResume((ex) -> {
return this.handleUnresolvedError(exchange, ex);
});
response.getClass();
return var10000.then(Mono.defer(response::setComplete));
}
将ServerHttpRequest和ServerHttpResponse转换为ServerWebExchange
protected ServerWebExchange createExchange(ServerHttpRequest request, ServerHttpResponse response) {
return new DefaultServerWebExchange(request, response, this.sessionManager, this.getCodecConfigurer(), this.getLocaleContextResolver(), this.applicationContext);
}
Mono<Void> handle(ServerWebExchange exchange);
主要用于Gateway中过滤链的创建
private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
return (List)filters.stream().map((filter) -> {
GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
if (filter instanceof Ordered) {
int order = ((Ordered)filter).getOrder();
return new OrderedGatewayFilter(gatewayFilter, order);
} else {
return gatewayFilter;
}
}).collect(Collectors.toList());
}
public Mono<Void> handle(ServerWebExchange exchange) {
Route route = (Route)exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
List<GatewayFilter> gatewayFilters = route.getFilters();
List<GatewayFilter> combined = new ArrayList(this.globalFilters);
combined.addAll(gatewayFilters);
AnnotationAwareOrderComparator.sort(combined);
if (logger.isDebugEnabled()) {
logger.debug("Sorted gatewayFilterFactories: " + combined);
}
return (new DefaultGatewayFilterChain(combined)).filter(exchange);
}
处理资源请求。
检查配置的位置列表中是否存在请求的资源。如果资源不存在,将向客户端返回404响应。如果资源存在,则将检查请求是否存在Last Modified标头,并将其值与给定资源的最后修改的时间戳进行比较,如果Last Modified值更大,则返回304状态代码。如果资源比“上次修改”的值新,或者标头不存在,则资源的内容资源将写入到响应中,缓存标头将在一年后过期。
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
return getResource(exchange)
.switchIfEmpty(Mono.defer(() -> {
logger.debug(exchange.getLogPrefix() + "Resource not found");
return Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND));
}))
.flatMap(resource -> {
try {
if (HttpMethod.OPTIONS.matches(exchange.getRequest().getMethodValue())) {
exchange.getResponse().getHeaders().add("Allow", "GET,HEAD,OPTIONS");
return Mono.empty();
}
// Supported methods and required session
HttpMethod httpMethod = exchange.getRequest().getMethod();
if (!SUPPORTED_METHODS.contains(httpMethod)) {
return Mono.error(new MethodNotAllowedException(
exchange.getRequest().getMethodValue(), SUPPORTED_METHODS));
}
// Header phase
if (exchange.checkNotModified(Instant.ofEpochMilli(resource.lastModified()))) {
logger.trace(exchange.getLogPrefix() + "Resource not modified");
return Mono.empty();
}
// Apply cache settings, if any
CacheControl cacheControl = getCacheControl();
if (cacheControl != null) {
exchange.getResponse().getHeaders().setCacheControl(cacheControl);
}
// Check the media type for the resource
MediaType mediaType = MediaTypeFactory.getMediaType(resource).orElse(null);
setHeaders(exchange, resource, mediaType);
// Content phase
ResourceHttpMessageWriter writer = getResourceHttpMessageWriter();
Assert.state(writer != null, "No ResourceHttpMessageWriter");
return writer.write(Mono.just(resource),
null, ResolvableType.forClass(Resource.class), mediaType,
exchange.getRequest(), exchange.getResponse(),
Hints.from(Hints.LOG_PREFIX_HINT, exchange.getLogPrefix()));
}
catch (IOException ex) {
return Mono.error(ex);
}
});
}
@Nullable
private List<HandlerMapping> handlerMappings;
@Nullable
private List<HandlerAdapter> handlerAdapters;
@Nullable
private List<HandlerResultHandler> resultHandlers;
protected void initStrategies(ApplicationContext context) {
Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerMapping.class, true, false);
ArrayList<HandlerMapping> mappings = new ArrayList<>(mappingBeans.values());
AnnotationAwareOrderComparator.sort(mappings);
this.handlerMappings = Collections.unmodifiableList(mappings);
Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerAdapter.class, true, false);
this.handlerAdapters = new ArrayList<>(adapterBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerResultHandler.class, true, false);
this.resultHandlers = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(this.resultHandlers);
}
每次执行请求,都会到当前方法中
1.根据ServerWebExchange获取到对应的HandlerMapping。
2.在从HandlerMapping中获取到对应的Handler。
3.根据Handler选取对应的HandlerAdapter。由HandlerAdapter执行方法。
4.根据执行结果,选择对应的HandlerResultHandler。由其处理结果返回值。
@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));
}
返回此请求的处理器
Mono<Object> getHandler(ServerWebExchange exchange);
getHandler:根据请求获取到对应的Handler
1.通过getHandlerInternal方法获取到对应的控制器。
2.在通过map函数判断请求是否保护CORS,如则对Handler添加对应的信息。
@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;
});
}
1.启动读锁,防止多线程执行时候出现数据异常
2.通过lookuphandlerMethod方法获取HandlerMethod
3.释放读锁
@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();
}
}
1.通过addMatchingMappings方法,获取到对应匹配的数据
2.
@Nullable
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);
}
}
/**
* 新增匹配Mapping
*/
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, ServerWebExchange exchange) {
for (T mapping : mappings) {
T match = getMatchingMapping(mapping, exchange);
if (match != null) {
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}
Handler Methods 发现
1.由InitializingBean执行AfetrPropertiesSet方法
2.获取上下文中所有Bean名称
3.如果Bean名称的开头是否是”scopedTarget.”
4.如果是则执行handlerMethodsInitialzed,本方式是一个空方法。
5.如果不是则,则从上下文中获取对应类。
6.通过isHandler()方法判断类是否是Handler类型,这里在类RequeMappingHandlerMapping中判断逻辑是注解@RequestMapping或是@Controller
7.通过类返射,将所有方法和对应的关系都注册到MappingRegistry
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());
}
}
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());
}
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);
});
}
}
1.通过RequestMappingInfo中获取到指定的RequeMappingInfo
@Override
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, ServerWebExchange exchange) {
return info.getMatchingCondition(exchange);
}
1.请求方法不能为OPTION或空
2.比对请求参数,是否匹配。 默认是不匹配。
3.请求头中,是否包含指定的头内容(去除Accept, Content-Type) 默认不匹配
4.请求头Content-Type中设置的类型是否支持,默认支持所有
5.支持的媒体类型,默认支持所有。
6.请求路径匹配,当前请求路径和实现的请求路径匹配
7.请求持有者判断,默认不进行。
8.当上述条件都满足时,创建RequestMappingInfo对象。
public RequestMappingInfo getMatchingCondition(ServerWebExchange exchange) {
RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(exchange);
if (methods == null) {
return null;
}
ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(exchange);
if (params == null) {
return null;
}
HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(exchange);
if (headers == null) {
return null;
}
// Match "Content-Type" and "Accept" (parsed ones and cached) before patterns
ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(exchange);
if (consumes == null) {
return null;
}
ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(exchange);
if (produces == null) {
return null;
}
PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(exchange);
if (patterns == null) {
return null;
}
RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(exchange);
if (custom == null) {
return null;
}
return new RequestMappingInfo(this.name, patterns,
methods, params, headers, consumes, produces, custom.getCondition());
}
@Nullable
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
protected RequestMappingInfo createRequestMappingInfo(
RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {
RequestMappingInfo.Builder builder = RequestMappingInfo
.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
.methods(requestMapping.method())
.params(requestMapping.params())
.headers(requestMapping.headers())
.consumes(requestMapping.consumes())
.produces(requestMapping.produces())
.mappingName(requestMapping.name());
if (customCondition != null) {
builder.customCondition(customCondition);
}
return builder.options(this.config).build();
}
判断是否是Handler
@Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
@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);
}
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);
}
private Object handleMatch(Object handler, PathPattern bestMatch, PathContainer pathWithinMapping,
ServerWebExchange exchange) {
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
validateHandler(handler, exchange);
exchange.getAttributes().put(BEST_MATCHING_HANDLER_ATTRIBUTE, handler);
exchange.getAttributes().put(BEST_MATCHING_PATTERN_ATTRIBUTE, bestMatch);
exchange.getAttributes().put(PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, pathWithinMapping);
return handler;
}
注册Handler
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
Assert.notNull(urlPath, "URL path must not be null");
Assert.notNull(handler, "Handler object must not be null");
Object resolvedHandler = handler;
// Parse path pattern
urlPath = prependLeadingSlash(urlPath);
PathPattern pattern = getPathPatternParser().parse(urlPath);
if (this.handlerMap.containsKey(pattern)) {
Object existingHandler = this.handlerMap.get(pattern);
if (existingHandler != null && existingHandler != resolvedHandler) {
throw new IllegalStateException(
"Cannot map " + getHandlerDescription(handler) + " to [" + urlPath + "]: " +
"there is already " + getHandlerDescription(existingHandler) + " mapped.");
}
}
// Eagerly resolve handler if referencing singleton via name.
if (!this.lazyInitHandlers && handler instanceof String) {
String handlerName = (String) handler;
if (obtainApplicationContext().isSingleton(handlerName)) {
resolvedHandler = obtainApplicationContext().getBean(handlerName);
}
}
// Register resolved handler
this.handlerMap.put(pattern, resolvedHandler);
if (logger.isTraceEnabled()) {
logger.trace("Mapped [" + urlPath + "] onto " + getHandlerDescription(handler));
}
}
初始化,并注册Handler
@Override
public void initApplicationContext() throws BeansException {
super.initApplicationContext();
registerHandlers(this.urlMap);
}
protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
if (urlMap.isEmpty()) {
logger.trace("No patterns in " + formatMappingName());
}
else {
for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
String url = entry.getKey();
Object handler = entry.getValue();
// Prepend with slash if not already present.
if (!url.startsWith("/")) {
url = "/" + url;
}
// Remove whitespace from handler bean name.
if (handler instanceof String) {
handler = ((String) handler).trim();
}
registerHandler(url, handler);
}
if (logger.isDebugEnabled()) {
logger.debug("Patterns " + getHandlerMap().keySet() + " in " + formatMappingName());
}
}
}
初始化执行
1.由InitializingBean执行AfetrPropertiesSet方法
2.如果消息读物为空,通过ServerCodeConfigurer类创建
3.如果routerFunction(路由方法),为空,则通过initRouteFunctions方法创建
4.通过routerFunctions方法执行Lambda,从上下文件中获取Bean类型为RouterFunction.class类型的Bean。
@Override
public void afterPropertiesSet() throws Exception {
if (CollectionUtils.isEmpty(this.messageReaders)) {
ServerCodecConfigurer codecConfigurer = ServerCodecConfigurer.create();
this.messageReaders = codecConfigurer.getReaders();
}
if (this.routerFunction == null) {
initRouterFunctions();
}
}
/**
* Initialized the router functions by detecting them in the application context.
*/
protected void initRouterFunctions() {
List<RouterFunction<?>> routerFunctions = routerFunctions();
this.routerFunction = routerFunctions.stream().reduce(RouterFunction::andOther).orElse(null);
logRouterFunctions(routerFunctions);
}
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());
}
获取执行方法
@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();
}
}
是否执行当前Handler
boolean supports(Object handler);
执行Handler并返回结果
Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler);
执行执行的Handler
public boolean supports(Object handler) {
return handler instanceof HandlerMethod;
}
执行
@Override
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Assert.state(this.methodResolver != null && this.modelInitializer != null, "Not initialized");
InitBinderBindingContext bindingContext = new InitBinderBindingContext(
getWebBindingInitializer(), this.methodResolver.getInitBinderMethods(handlerMethod));
InvocableHandlerMethod invocableMethod = this.methodResolver.getRequestMappingMethod(handlerMethod);
Function<Throwable, Mono<HandlerResult>> exceptionHandler =
ex -> handleException(ex, handlerMethod, bindingContext, exchange);
return this.modelInitializer
.initModel(handlerMethod, bindingContext, exchange)
.then(Mono.defer(() -> invocableMethod.invoke(exchange, bindingContext)))
.doOnNext(result -> result.setExceptionHandler(exceptionHandler))
.doOnNext(result -> bindingContext.saveModel())
.onErrorResume(exceptionHandler);
}
public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
Mono<Object> valueMono;
ResolvableType valueType;
ReactiveAdapter adapter = getAdapter(result);
if (adapter != null) {
if (adapter.isMultiValue()) {
throw new IllegalArgumentException(
"Multi-value reactive types not supported in view resolution: " + result.getReturnType());
}
valueMono = (result.getReturnValue() != null ?
Mono.from(adapter.toPublisher(result.getReturnValue())) : Mono.empty());
valueType = (adapter.isNoValue() ? ResolvableType.forClass(Void.class) :
result.getReturnType().getGeneric());
}
else {
valueMono = Mono.justOrEmpty(result.getReturnValue());
valueType = result.getReturnType();
}
return valueMono
.switchIfEmpty(exchange.isNotModified() ? Mono.empty() : NO_VALUE_MONO)
.flatMap(returnValue -> {
Mono<List<View>> viewsMono;
Model model = result.getModel();
MethodParameter parameter = result.getReturnTypeSource();
Locale locale = LocaleContextHolder.getLocale(exchange.getLocaleContext());
Class<?> clazz = valueType.toClass();
if (clazz == Object.class) {
clazz = returnValue.getClass();
}
if (returnValue == NO_VALUE || clazz == void.class || clazz == Void.class) {
viewsMono = resolveViews(getDefaultViewName(exchange), locale);
}
else if (CharSequence.class.isAssignableFrom(clazz) && !hasModelAnnotation(parameter)) {
viewsMono = resolveViews(returnValue.toString(), locale);
}
else if (Rendering.class.isAssignableFrom(clazz)) {
Rendering render = (Rendering) returnValue;
HttpStatus status = render.status();
if (status != null) {
exchange.getResponse().setStatusCode(status);
}
exchange.getResponse().getHeaders().putAll(render.headers());
model.addAllAttributes(render.modelAttributes());
Object view = render.view();
if (view == null) {
view = getDefaultViewName(exchange);
}
viewsMono = (view instanceof String ? resolveViews((String) view, locale) :
Mono.just(Collections.singletonList((View) view)));
}
else if (Model.class.isAssignableFrom(clazz)) {
model.addAllAttributes(((Model) returnValue).asMap());
viewsMono = resolveViews(getDefaultViewName(exchange), locale);
}
else if (Map.class.isAssignableFrom(clazz) && !hasModelAnnotation(parameter)) {
model.addAllAttributes((Map<String, ?>) returnValue);
viewsMono = resolveViews(getDefaultViewName(exchange), locale);
}
else if (View.class.isAssignableFrom(clazz)) {
viewsMono = Mono.just(Collections.singletonList((View) returnValue));
}
else {
String name = getNameForReturnValue(parameter);
model.addAttribute(name, returnValue);
viewsMono = resolveViews(getDefaultViewName(exchange), locale);
}
BindingContext bindingContext = result.getBindingContext();
updateBindingResult(bindingContext, exchange);
return viewsMono.flatMap(views -> render(views, model.asMap(), bindingContext, exchange));
});
}
通过代理执行对应的方法
public Mono<Void> handle(ServerWebExchange exchange) {
return this.delegate.handle(exchange);
}
完成过滤链的创建
public FilteringWebHandler(WebHandler handler, List<WebFilter> filters) {
super(handler);
this.chain = new DefaultWebFilterChain(handler, filters);
}
初始化
public ExceptionHandlingWebHandler(WebHandler delegate, List<WebExceptionHandler> handlers) {
super(delegate);
List<WebExceptionHandler> handlersToUse = new ArrayList();
handlersToUse.add(new CheckpointInsertingHandler());
handlersToUse.addAll(handlers);
this.exceptionHandlers = Collections.unmodifiableList(handlersToUse);
}
执行
1.先执行正常的WebHandler
2.执行完成之后,如果异常则执行所有异常类。
public Mono<Void> handle(ServerWebExchange exchange) {
Mono<Void> completion;
try {
completion = super.handle(exchange);
}
catch (Throwable ex) {
completion = Mono.error(ex);
}
for (WebExceptionHandler handler : this.exceptionHandlers) {
completion = completion.onErrorResume(ex -> handler.handle(exchange, ex));
}
return completion;
}
public Mono<Void> handle(ServerWebExchange exchange) {
return Mono.defer(() -> {
ServerRequest request = new DefaultServerRequest(exchange, this.strategies.messageReaders());
addAttributes(exchange, request);
return this.routerFunction.route(request)
.defaultIfEmpty(notFound())
.flatMap(handlerFunction -> wrapException(() -> handlerFunction.handle(request)))
.flatMap(response -> wrapException(() -> response.writeTo(exchange,
new HandlerStrategiesResponseContext(this.strategies))));
});
}
private void addAttributes(ServerWebExchange exchange, ServerRequest request) {
Map<String, Object> attributes = exchange.getAttributes();
attributes.put(REQUEST_ATTRIBUTE, request);
}
Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain);
根据spring.factories有以下自动启类
HttpHandler完成了WebFilterChain的装配,使所有HTTP请求都经过WebFilterChain过滤执行。
@Configuration(proxyBeanMethods = false)
public static class AnnotationConfig {
@Bean
public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider) {
HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(this.applicationContext).build();
WebFluxProperties properties = propsProvider.getIfAvailable();
if (properties != null && StringUtils.hasText(properties.getBasePath())) {
Map<String, HttpHandler> handlersMap = Collections.singletonMap(properties.getBasePath(), httpHandler);
return new ContextPathCompositeHandler(handlersMap);
}
return httpHandler;
}
}
创建WebHttpHandlerBuilder
1.通过上下文Bean获取名称为"webHandler"且类为WebHandler
2.通过上下文获取所有的WebFilter并进行排序。
3.对所有WebFilter类进行处理和过滤
4.通过上下文获取所有的WebExceptionHandler类并进行排序。
5.对所有WebExceptionHandler类进行处理和过滤
6.通过上下文Bean获取名称为"webSessionManager"且类为WebSessionManager
7.通过上下文Bean获取名称为"serverCodecConfigurer"且类为ServerCodecConfigurer
8.通过上下文Bean获取名称为"localeContextResolver"且类为LocaleContextResolver
9.通过上下文Bean获取名称为"forwardedHeaderTransformer"且类为ForwardedHeaderTransformer
public static WebHttpHandlerBuilder applicationContext(ApplicationContext context) {
WebHttpHandlerBuilder builder = new WebHttpHandlerBuilder(
context.getBean(WEB_HANDLER_BEAN_NAME, WebHandler.class), context);
List<WebFilter> webFilters = context
.getBeanProvider(WebFilter.class)
.orderedStream()
.collect(Collectors.toList());
builder.filters(filters -> filters.addAll(webFilters));
List<WebExceptionHandler> exceptionHandlers = context
.getBeanProvider(WebExceptionHandler.class)
.orderedStream()
.collect(Collectors.toList());
builder.exceptionHandlers(handlers -> handlers.addAll(exceptionHandlers));
try {
builder.sessionManager(
context.getBean(WEB_SESSION_MANAGER_BEAN_NAME, WebSessionManager.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Fall back on default
}
try {
builder.codecConfigurer(
context.getBean(SERVER_CODEC_CONFIGURER_BEAN_NAME, ServerCodecConfigurer.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Fall back on default
}
try {
builder.localeContextResolver(
context.getBean(LOCALE_CONTEXT_RESOLVER_BEAN_NAME, LocaleContextResolver.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Fall back on default
}
try {
builder.forwardedHeaderTransformer(
context.getBean(FORWARDED_HEADER_TRANSFORMER_BEAN_NAME, ForwardedHeaderTransformer.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Fall back on default
}
return builder;
}
1.HttpHandler的构造器
2.创建WebFilterChain过滤器通过FilteringWebHandler创建DefaultWebFilterChain,而DefaultWebFilterChain实现了WebFilterChain。
3.创建ExceptionHandlingWebHandler并将FilteringWebHandler设置进去。
4.创建HttpWebHandlerAdapter,并将WebHandler设置到adapted中。
5.
public HttpHandler build() {
WebHandler decorated = new FilteringWebHandler(this.webHandler, this.filters);
WebHandler decorated = new ExceptionHandlingWebHandler(decorated, this.exceptionHandlers);
HttpWebHandlerAdapter adapted = new HttpWebHandlerAdapter(decorated);
if (this.sessionManager != null) {
adapted.setSessionManager(this.sessionManager);
}
if (this.codecConfigurer != null) {
adapted.setCodecConfigurer(this.codecConfigurer);
}
if (this.localeContextResolver != null) {
adapted.setLocaleContextResolver(this.localeContextResolver);
}
if (this.forwardedHeaderTransformer != null) {
adapted.setForwardedHeaderTransformer(this.forwardedHeaderTransformer);
}
if (this.applicationContext != null) {
adapted.setApplicationContext(this.applicationContext);
}
adapted.afterPropertiesSet();
return adapted;
}
public FilteringWebHandler(WebHandler handler, List<WebFilter> filters) {
super(handler);
this.chain = new DefaultWebFilterChain(handler, filters);
}
实现了WebFilterChain
初始化
1.创建DefaultWebFilterChain
2.通过initChain来创建过滤链,如果WebFliter存在多个。则创建WebFliter的链。
public DefaultWebFilterChain(WebHandler handler, List<WebFilter> filters) {
Assert.notNull(handler, "WebHandler is required");
this.allFilters = Collections.unmodifiableList(filters);
this.handler = handler;
DefaultWebFilterChain chain = initChain(filters, handler);
this.currentFilter = chain.currentFilter;
this.chain = chain.chain;
}
private static DefaultWebFilterChain initChain(List<WebFilter> filters, WebHandler handler) {
DefaultWebFilterChain chain = new DefaultWebFilterChain(filters, handler, (WebFilter)null, (DefaultWebFilterChain)null);
for(ListIterator<? extends WebFilter> iterator = filters.listIterator(filters.size()); iterator.hasPrevious(); chain = new DefaultWebFilterChain(filters, handler, (WebFilter)iterator.previous(), chain)) {
}
return chain;
}
过滤链执行
1.通过Mono.defer()完成订阅功能,当有事件发布(如:前端发起请求)的时候就可以收到。
2.判断当前currentFilter是否为空,不为空则执行WebFilter的过滤链,
3.当WebFilter执行完之后,执行WebHandler。
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.defer(() -> {
return this.currentFilter != null && this.chain != null ? this.invokeFilter(this.currentFilter, this.chain, exchange) : this.handler.handle(exchange);
});
}
private Mono<Void> invokeFilter(WebFilter current, DefaultWebFilterChain chain, ServerWebExchange exchange) {
String currentName = current.getClass().getName();
return current.filter(exchange, chain).checkpoint(currentName + " [DefaultWebFilterChain]");
}
默认支持4中方式自启动服务器:Tomcat、Jetty、Undertow、Netty
@Import({ ReactiveWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ReactiveWebServerFactoryConfiguration.EmbeddedTomcat.class,
ReactiveWebServerFactoryConfiguration.EmbeddedJetty.class,
ReactiveWebServerFactoryConfiguration.EmbeddedUndertow.class,
ReactiveWebServerFactoryConfiguration.EmbeddedNetty.class })
Spring-boot-starter-webflux默认启动是nettty
org.springframework.boot
spring-boot-starter-reactor-netty
2.3.12.RELEASE
compile
继承自HiddenHttpMethodFilter并实现OrderedWebFilter,而HiddenHttpMethodFilter
实现了WebFilter
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.webflux.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
1.引入EnableWebFluxConfiguration类,在初始化当前类之前完成该类初始化。
2.启动配置参数ResourceProperties类和WebFluxProperties类
3.通过addResourceHandlers(添加资源Handlers)完成对"/webjars/**"目录和"classpath:/META-INF/resources/webjars/"目录资源的加载。 还可以通过WebFluxProperties配置添加自定义资源目录和本地目录。
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ ResourceProperties.class, WebFluxProperties.class })
@Import({ EnableWebFluxConfiguration.class })
public static class WebFluxConfig implements WebFluxConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
if (!registry.hasMappingForPattern("/webjars/**")) {
ResourceHandlerRegistration registration = registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
configureResourceCaching(registration);
customizeResourceHandlerRegistration(registration);
}
String staticPathPattern = this.webFluxProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
ResourceHandlerRegistration registration = registry.addResourceHandler(staticPathPattern)
.addResourceLocations(this.resourceProperties.getStaticLocations());
configureResourceCaching(registration);
customizeResourceHandlerRegistration(registration);
}
}
}
继承自DelegatingWebFluxConfiguration,而DelegatingWebFluxConfiguration继承自WebFluxConfigurationSupport
1.注解@Configuration实现自动转为Bean
@Configuration(proxyBeanMethods = false)
public static class EnableWebFluxConfiguration extends DelegatingWebFluxConfiguration {
private final WebFluxProperties webFluxProperties;
private final WebFluxRegistrations webFluxRegistrations;
public EnableWebFluxConfiguration(WebFluxProperties webFluxProperties,
ObjectProvider<WebFluxRegistrations> webFluxRegistrations) {
this.webFluxProperties = webFluxProperties;
this.webFluxRegistrations = webFluxRegistrations.getIfUnique();
}
@Bean
@Override
public FormattingConversionService webFluxConversionService() {
Format format = this.webFluxProperties.getFormat();
WebConversionService conversionService = new WebConversionService(new DateTimeFormatters()
.dateFormat(format.getDate()).timeFormat(format.getTime()).dateTimeFormat(format.getDateTime()));
addFormatters(conversionService);
return conversionService;
}
@Bean
@Override
public Validator webFluxValidator() {
if (!ClassUtils.isPresent("javax.validation.Validator", getClass().getClassLoader())) {
return super.webFluxValidator();
}
return ValidatorAdapter.get(getApplicationContext(), getValidator());
}
@Override
protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
if (this.webFluxRegistrations != null) {
RequestMappingHandlerAdapter adapter = this.webFluxRegistrations.getRequestMappingHandlerAdapter();
if (adapter != null) {
return adapter;
}
}
return super.createRequestMappingHandlerAdapter();
}
@Override
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
if (this.webFluxRegistrations != null) {
RequestMappingHandlerMapping mapping = this.webFluxRegistrations.getRequestMappingHandlerMapping();
if (mapping != null) {
return mapping;
}
}
return super.createRequestMappingHandlerMapping();
}
}
当异常时候的处理
@Bean
@ConditionalOnMissingBean(value = ErrorWebExceptionHandler.class, search = SearchStrategy.CURRENT)
@Order(-1)
public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes,
ResourceProperties resourceProperties, ObjectProvider<ViewResolver> viewResolvers,
ServerCodecConfigurer serverCodecConfigurer, ApplicationContext applicationContext) {
DefaultErrorWebExceptionHandler exceptionHandler = new DefaultErrorWebExceptionHandler(errorAttributes,
resourceProperties, this.serverProperties.getError(), applicationContext);
exceptionHandler.setViewResolvers(viewResolvers.orderedStream().collect(Collectors.toList()));
exceptionHandler.setMessageWriters(serverCodecConfigurer.getWriters());
exceptionHandler.setMessageReaders(serverCodecConfigurer.getReaders());
return exceptionHandler;
}
@Bean
@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
public DefaultErrorAttributes errorAttributes() {
return new DefaultErrorAttributes();
}
@Bean
@Lazy
@Order(0)
@ConditionalOnBean(ClientHttpConnector.class)
public WebClientCustomizer clientConnectorCustomizer(ClientHttpConnector clientHttpConnector) {
return (builder) -> builder.clientConnector(clientHttpConnector);
}
@Import({ ClientHttpConnectorConfiguration.ReactorNetty.class, ClientHttpConnectorConfiguration.JettyClient.class })
ReactorNetty
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(reactor.netty.http.client.HttpClient.class)
@ConditionalOnMissingBean(ClientHttpConnector.class)
public static class ReactorNetty {
@Bean
@ConditionalOnMissingBean
public ReactorResourceFactory reactorClientResourceFactory() {
return new ReactorResourceFactory();
}
@Bean
@Lazy
public ReactorClientHttpConnector reactorClientHttpConnector(ReactorResourceFactory reactorResourceFactory,
ObjectProvider<ReactorNettyHttpClientMapper> mapperProvider) {
ReactorNettyHttpClientMapper mapper = mapperProvider.orderedStream()
.reduce((before, after) -> (client) -> after.configure(before.configure(client)))
.orElse((client) -> client);
return new ReactorClientHttpConnector(reactorResourceFactory, mapper::configure);
}
}
@AutoConfigureAfter({ CodecsAutoConfiguration.class,
ClientHttpConnectorAutoConfiguration.class })
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
public WebClient.Builder webClientBuilder(ObjectProvider<WebClientCustomizer> customizerProvider) {
WebClient.Builder builder = WebClient.builder();
customizerProvider.orderedStream().forEach((customizer) -> customizer.customize(builder));
return builder;
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(CodecCustomizer.class)
protected static class WebClientCodecsConfiguration {
@Bean
@ConditionalOnMissingBean
@Order(0)
public WebClientCodecCustomizer exchangeStrategiesCustomizer(ObjectProvider<CodecCustomizer> codecCustomizers) {
return new WebClientCodecCustomizer(codecCustomizers.orderedStream().collect(Collectors.toList()));
}
}