webflux系列--源码解析二

accept包

RequestedContentTypeResolver

处理mediaType的接口。

public interface RequestedContentTypeResolver {
    
    
	List<MediaType> MEDIA_TYPE_ALL_LIST = Collections.singletonList(MediaType.ALL);

	/**将给定的请求解析为请求的媒体类型列表。返回的列表首先按特异性排序,然后按质量参数排序。*/
	List<MediaType> resolveMediaTypes(ServerWebExchange exchange);

}

RequestedContentTypeResolver

FixedContentTypeResolver

解析器始终解析为固定列表的MediaType。这可以用作“最后一行”策略,当客户端没有请求任何媒体类型时提供解析。

public class FixedContentTypeResolver implements RequestedContentTypeResolver {
    
    
	private final List<MediaType> contentTypes;
}

HeaderContentTypeResolver

根据请求的“Accept” header 解析。

public class HeaderContentTypeResolver implements RequestedContentTypeResolver {
    
    

	@Override
	public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) throws NotAcceptableStatusException {
    
    
		try {
    
    
            //Accept header。
			List<MediaType> mediaTypes = exchange.getRequest().getHeaders().getAccept();
			MediaType.sortBySpecificityAndQuality(mediaTypes);
			return (!CollectionUtils.isEmpty(mediaTypes) ? mediaTypes : MEDIA_TYPE_ALL_LIST);
		}
		catch (InvalidMediaTypeException ex) {
    
    
			String value = exchange.getRequest().getHeaders().getFirst("Accept");
			throw new NotAcceptableStatusException(
					"Could not parse 'Accept' header [" + value + "]: " + ex.getMessage());
		}
	}

}

ParameterContentTypeResolver

根据查询参数解析MediaType。参数自定义。

public class ParameterContentTypeResolver implements RequestedContentTypeResolver {
    
    

	/** Primary lookup for media types by key (e.g. "json" -> "application/json") */
	private final Map<String, MediaType> mediaTypes = new ConcurrentHashMap<>(64);

	private String parameterName = "format";
	@Override
	public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) throws NotAcceptableStatusException {
    
    
		String key = exchange.getRequest().getQueryParams().getFirst(getParameterName());
		if (!StringUtils.hasText(key)) {
    
    
			return MEDIA_TYPE_ALL_LIST;
		}
        //通过map 查找对应MediaType
		key = formatKey(key);
		MediaType match = this.mediaTypes.get(key);
		if (match == null) {
    
    
			match = MediaTypeFactory.getMediaType("filename." + key)
					.orElseThrow(() -> {
    
    
						List<MediaType> supported = new ArrayList<>(this.mediaTypes.values());
						return new NotAcceptableStatusException(supported);
					});
		}
		this.mediaTypes.putIfAbsent(key, match);
		return Collections.singletonList(match);
	}
    
}	

result包

HandlerResultHandlerSupport

HandlerResultHandler的基类,支持内容协商和访问ReactiveAdapter注册表。

public abstract class HandlerResultHandlerSupport implements Ordered {
    
    
	private static final List<MediaType> ALL_APPLICATION_MEDIA_TYPES =
			Arrays.asList(MediaType.ALL, new MediaType("application"));

	private final RequestedContentTypeResolver contentTypeResolver;
	private final ReactiveAdapterRegistry adapterRegistry;
	private int order = LOWEST_PRECEDENCE;
	
	/** 获取最合适的mediaType*/
	@Nullable
	protected MediaType selectMediaType(
			ServerWebExchange exchange, Supplier<List<MediaType>> producibleTypesSupplier) {
    
    
		//如果header中有contentType,直接返回。
		MediaType contentType = exchange.getResponse().getHeaders().getContentType();
		if (contentType != null && contentType.isConcrete()) {
    
    
			if (logger.isDebugEnabled()) {
    
    
				logger.debug(exchange.getLogPrefix() + "Found 'Content-Type:" + contentType + "' in response");
			}
			return contentType;
		}
		//查找合适的Mediatype
		List<MediaType> acceptableTypes = getAcceptableTypes(exchange);
		List<MediaType> producibleTypes = getProducibleTypes(exchange, producibleTypesSupplier);

		Set<MediaType> compatibleMediaTypes = new LinkedHashSet<>();
		for (MediaType acceptable : acceptableTypes) {
    
    
			for (MediaType producible : producibleTypes) {
    
    
				if (acceptable.isCompatibleWith(producible)) {
    
    
					compatibleMediaTypes.add(selectMoreSpecificMediaType(acceptable, producible));
				}
			}
		}

		List<MediaType> result = new ArrayList<>(compatibleMediaTypes);
		MediaType.sortBySpecificityAndQuality(result);

		MediaType selected = null;
		for (MediaType mediaType : result) {
    
    
			if (mediaType.isConcrete()) {
    
    
				selected = mediaType;
				break;
			}
			else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {
    
    
				selected = MediaType.APPLICATION_OCTET_STREAM;
				break;
			}
		}

		if (selected != null) {
    
    
			selected = selected.removeQualityValue();
			... LOG ....
		}
		else if (logger.isDebugEnabled()) {
    
    
			... LOG ... 
		}

		return selected;
	}
    
}	

View包

View

View接口用于渲染HandlerResult。视图通常是通过名称来选择的,并使用ViewResolver来解析,例如将其与HTML模板匹配。此外,视图可以基于模型中包含的多个属性呈现。视图还可以选择从模型中选择一个属性,使用任何现有的编码器来呈现替代媒体类型。

public interface View {
    
    
	String BINDING_CONTEXT_ATTRIBUTE = View.class.getName() + ".bindingContext";
	/**
	 * Return the list of media types this View supports, or an empty list.
	 */
	default List<MediaType> getSupportedMediaTypes() {
    
    
		return Collections.emptyList();
	}

	/**
	 * Whether this View does rendering by performing a redirect.
	 */
	default boolean isRedirectView() {
    
    
		return false;
	}

	/** 渲染 HandlerResult*/
	Mono<Void> render(@Nullable Map<String, ?> model, @Nullable MediaType contentType, ServerWebExchange exchange);

}

Diagram

View

AbstractView

ublic abstract class AbstractView implements View, BeanNameAware, ApplicationContextAware {
    
    

	/** Well-known name for the RequestDataValueProcessor in the bean factory. */
	public static final String REQUEST_DATA_VALUE_PROCESSOR_BEAN_NAME = "requestDataValueProcessor";
	protected final Log logger = LogFactory.getLog(getClass());
	private final ReactiveAdapterRegistry adapterRegistry;
	private final List<MediaType> mediaTypes = new ArrayList<>(4);
	private Charset defaultCharset = StandardCharsets.UTF_8;
	@Nullable
	private String requestContextAttribute;
	@Nullable
	private String beanName;
	@Nullable
	private ApplicationContext applicationContext;
    
	/**渲染Model*/
	@Override
	public Mono<Void> render(@Nullable Map<String, ?> model, @Nullable MediaType contentType,
			ServerWebExchange exchange) {
    
    
	... ... 
        //设置contentType
		if (contentType != null) {
    
    
			exchange.getResponse().getHeaders().setContentType(contentType);
		}

		return getModelAttributes(model, exchange).flatMap(mergedModel -> {
    
    
			// Expose RequestContext?
			if (this.requestContextAttribute != null) {
    
    
				mergedModel.put(this.requestContextAttribute, createRequestContext(exchange, mergedModel));
			}
            //渲染model
			return renderInternal(mergedModel, contentType, exchange);
		});
	}
    
}

AbstractUrlBasedView

基于Url的视图渲染

public abstract class AbstractUrlBasedView extends AbstractView implements InitializingBean {
    
    

	@Nullable
	private String url;
}	

RedirectView

重定向到一个Url。

ScriptTemplateView

解释性模板视图。

FreeMarkerView

FreeMarker视图

ViewResolver

ViewResolver通过name解析成View。

public interface ViewResolver {
    
    
	Mono<View> resolveViewName(String viewName, Locale locale);
}

Diagram

image-20210113194331280

Rendering

/**Public API for HTML rendering
*/
public interface Rendering {
    
    
	Object view();
	/**
	 * Return attributes to add to the model.
	 */
	Map<String, Object> modelAttributes();

	/**
	 * Return the HTTP status to set the response to.
	 */
	@Nullable
	HttpStatus status();

	/**
	 * Return headers to add to the response.
	 */
	HttpHeaders headers();
}

condition包

RequestCondition

RequestCondition 对一个请求匹配条件的概念建模。最终的实现类可能是针对以下情况之一:路径匹配,头部匹配,请求参数匹配,可产生MIME匹配,可消费MIME匹配,请求方法匹配,或者是以上各种情况的匹配条件的一个组合。

public interface RequestCondition<T> {
    
    

	T combine(T other);

	@Nullable
	T getMatchingCondition(ServerWebExchange exchange);

	int compareTo(T other, ServerWebExchange exchange);

}

RequestCondition

method包

类似Mvc,用于处理 Method类型的handler。

function包

一些常用的函数式接口及实现。

socket包

反应式WebSocket交互的抽象和支持类。

WebSocketHandler

public interface WebSocketHandler {
    
    

	default List<String> getSubProtocols() {
    
    
		return Collections.emptyList();
	}
	Mono<Void> handle(WebSocketSession session);
}

猜你喜欢

转载自blog.csdn.net/demon7552003/article/details/112598914