/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.handler;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.servlet.DispatcherType;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.core.Ordered;
import org.springframework.lang.Nullable;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.util.PathMatcher;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.context.request.WebRequestInterceptor;
import org.springframework.web.context.support.WebApplicationObjectSupport;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.CorsProcessor;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.cors.DefaultCorsProcessor;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.util.UrlPathHelper;
/**
* {@link org.springframework.web.servlet.HandlerMapping}的抽象基类
* 实现。支持排序,默认处理程序,处理程序拦截器,
* 包括按路径模式映射的处理程序拦截器。
*
* <p>注意:此基类不支持<i>
* {@link #PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE}。支持此属性
* 取决于具体的子类,通常基于请求URL映射。
*
* @author Juergen Hoeller
* @author Rossen Stoyanchev
* @see #getHandlerInternal
* @see #setDefaultHandler
* @see #setAlwaysUseFullPath
* @see #setUrlDecode
* @see org.springframework.util.AntPathMatcher
* @see #setInterceptors
* @see org.springframework.web.servlet.HandlerInterceptor
* @since 07.04.2003
*/
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
implements HandlerMapping, Ordered, BeanNameAware {
@Nullable
private Object defaultHandler;
private UrlPathHelper urlPathHelper = new UrlPathHelper();
private PathMatcher pathMatcher = new AntPathMatcher();
private final List<Object> interceptors = new ArrayList<>();
private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<>();
@Nullable
private CorsConfigurationSource corsConfigurationSource;
private CorsProcessor corsProcessor = new DefaultCorsProcessor();
private int order = Ordered.LOWEST_PRECEDENCE; // default: same as non-Ordered
@Nullable
private String beanName;
/**
* 设置此处理程序映射的默认处理程序。
* 如果未找到特定映射,则将返回此处理程序。
* <p>默认为{@code null},表示没有默认处理程序。
*/
public void setDefaultHandler(@Nullable Object defaultHandler) {
this.defaultHandler = defaultHandler;
}
/**
* 返回此处理程序映射的默认处理程序,
* 或{@code null}(如果没有)。
*/
@Nullable
public Object getDefaultHandler() {
return this.defaultHandler;
}
/**
* 基础{@link #setUrlPathHelper UrlPathHelper}上相同属性的快捷方式。
*
* @see org.springframework.web.util.UrlPathHelper#setAlwaysUseFullPath(boolean)
*/
public void setAlwaysUseFullPath(boolean alwaysUseFullPath) {
this.urlPathHelper.setAlwaysUseFullPath(alwaysUseFullPath);
if (this.corsConfigurationSource instanceof UrlBasedCorsConfigurationSource) {
((UrlBasedCorsConfigurationSource) this.corsConfigurationSource).setAlwaysUseFullPath(alwaysUseFullPath);
}
}
/**
* 基础{@link #setUrlPathHelper UrlPathHelper}上相同属性的快捷方式。
*
* @see org.springframework.web.util.UrlPathHelper#setUrlDecode(boolean)
*/
public void setUrlDecode(boolean urlDecode) {
this.urlPathHelper.setUrlDecode(urlDecode);
if (this.corsConfigurationSource instanceof UrlBasedCorsConfigurationSource) {
((UrlBasedCorsConfigurationSource) this.corsConfigurationSource).setUrlDecode(urlDecode);
}
}
/**
* 基础{@link #setUrlPathHelper UrlPathHelper}上相同属性的快捷方式。
*
* @see org.springframework.web.util.UrlPathHelper#setRemoveSemicolonContent(boolean)
*/
public void setRemoveSemicolonContent(boolean removeSemicolonContent) {
this.urlPathHelper.setRemoveSemicolonContent(removeSemicolonContent);
if (this.corsConfigurationSource instanceof UrlBasedCorsConfigurationSource) {
((UrlBasedCorsConfigurationSource) this.corsConfigurationSource).setRemoveSemicolonContent(removeSemicolonContent);
}
}
/**
* 设置UrlPathHelper以用于解析查找路径。
* <p>使用它使用自定义子类覆盖默认的UrlPathHelper,
* 或在多个HandlerMapping中共享通用的UrlPathHelper设置
* 和MethodNameResolvers。
*/
public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
Assert.notNull(urlPathHelper, "UrlPathHelper must not be null");
this.urlPathHelper = urlPathHelper;
if (this.corsConfigurationSource instanceof UrlBasedCorsConfigurationSource) {
((UrlBasedCorsConfigurationSource) this.corsConfigurationSource).setUrlPathHelper(urlPathHelper);
}
}
/**
* 返回UrlPathHelper实现以用于解析查找路径。
*/
public UrlPathHelper getUrlPathHelper() {
return this.urlPathHelper;
}
/**
* 设置PathMatcher实现以用于匹配URL路径
*针对已注册的网址格式。默认值为AntPathMatcher。
*
* @see org.springframework.util.AntPathMatcher
*/
public void setPathMatcher(PathMatcher pathMatcher) {
Assert.notNull(pathMatcher, "PathMatcher must not be null");
this.pathMatcher = pathMatcher;
if (this.corsConfigurationSource instanceof UrlBasedCorsConfigurationSource) {
((UrlBasedCorsConfigurationSource) this.corsConfigurationSource).setPathMatcher(pathMatcher);
}
}
/**
*返回PathMatcher实现以用于匹配URL路径
*针对已注册的网址格式.
*/
public PathMatcher getPathMatcher() {
return this.pathMatcher;
}
/**
* 设置拦截器以应用此处理程序映射所映射的所有处理程序。
* <p>支持的拦截器类型为HandlerInterceptor,WebRequestInterceptor和MappedInterceptor。
*映射的拦截器仅适用于与其路径模式匹配的请求URL。
*映射的拦截器bean在初始化期间也按类型检测。
*
* @param interceptors array of handler interceptors
* @see #adaptInterceptor
* @see org.springframework.web.servlet.HandlerInterceptor
* @see org.springframework.web.context.request.WebRequestInterceptor
*/
public void setInterceptors(Object... interceptors) {
this.interceptors.addAll(Arrays.asList(interceptors));
}
/**
* S等基于URL模式的“全局” CORS配置。默认情况下,第一个
*匹配的URL模式与处理程序的CORS配置(如果有)结合在一起。
*
* @see #setCorsConfigurationSource(CorsConfigurationSource)
* @since 4.2
*/
public void setCorsConfigurations(Map<String, CorsConfiguration> corsConfigurations) {
Assert.notNull(corsConfigurations, "corsConfigurations must not be null");
if (!corsConfigurations.isEmpty()) {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.setCorsConfigurations(corsConfigurations);
source.setPathMatcher(this.pathMatcher);
source.setUrlPathHelper(this.urlPathHelper);
source.setLookupPathAttributeName(LOOKUP_PATH);
this.corsConfigurationSource = source;
} else {
this.corsConfigurationSource = null;
}
}
/**
* 设置“全局” CORS配置源。默认情况下,第一个匹配的URL
*模式与处理程序的CORS配置(如果有)结合在一起。
*
* @see #setCorsConfigurations(Map)
* @since 5.1
*/
public void setCorsConfigurationSource(CorsConfigurationSource corsConfigurationSource) {
Assert.notNull(corsConfigurationSource, "corsConfigurationSource must not be null");
this.corsConfigurationSource = corsConfigurationSource;
}
/**
* 配置自定义{@link CorsProcessor}以应用匹配项
* {@link CorsConfiguration}进行请求。
* <p>默认使用{@link DefaultCorsProcessor}。
*
* @since 4.2
*/
public void setCorsProcessor(CorsProcessor corsProcessor) {
Assert.notNull(corsProcessor, "CorsProcessor must not be null");
this.corsProcessor = corsProcessor;
}
/**
* 返回配置的{@link CorsProcessor}。
*/
public CorsProcessor getCorsProcessor() {
return this.corsProcessor;
}
/**
* 指定此HandlerMapping bean的订单值。
* <p>默认值为{@code Ordered.LOWEST_PRECEDENCE},表示无序.
*
* @see org.springframework.core.Ordered#getOrder()
*/
public void setOrder(int order) {
this.order = order;
}
@Override
public int getOrder() {
return this.order;
}
@Override
public void setBeanName(String name) {
this.beanName = name;
}
protected String formatMappingName() {
return this.beanName != null ? "'" + this.beanName + "'" : "<unknown>";
}
/**
* 初始化拦截器.
*
* @see #extendInterceptors(java.util.List)
* @see #initInterceptors()
*/
@Override
protected void initApplicationContext() throws BeansException {
extendInterceptors(this.interceptors);
detectMappedInterceptors(this.adaptedInterceptors);
initInterceptors();
}
/**
* 子类可以覆盖的扩展钩子来注册其他拦截器,
*提供了已配置的拦截器(请参阅{@link #setInterceptors})。
* <p>将在{@link #initInterceptors()}修改指定的值之前被调用
*将拦截器插入{@link HandlerInterceptor}实例中。
* <p>默认实现为空。
*
* @param interceptors 配置的拦截器列表(绝不{@code null}),允许
*在现有拦截器之前和之后添加更多拦截器
*/
protected void extendInterceptors(List<Object> interceptors) {
}
/**
* 检测类型为{@link MappedInterceptor}的bean,并将其添加到映射的拦截器列表中。
* <p>除了可能提供的任何{@link MappedInterceptor MappedInterceptors}之外,还调用了此方法
*通过{@link #setInterceptors},默认情况下添加所有类型为{@link MappedInterceptor}的bean
*来自当前背景及其祖先。子类可以覆盖和完善此策略.
*
* @param mappedInterceptors 一个空白列表,将{@link MappedInterceptor}实例添加到
*/
protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
mappedInterceptors.addAll(
BeanFactoryUtils.beansOfTypeIncludingAncestors(
obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}
/**
* 初始化指定的拦截器,检查{@link MappedInterceptor MappedInterceptors}和
*调整{@link HandlerInterceptor}和{@link WebRequestInterceptor HandlerInterceptor}和
* {@link WebRequestInterceptor} s(如有必要)。
*
* @see #setInterceptors
* @see #adaptInterceptor
*/
protected void initInterceptors() {
if (!this.interceptors.isEmpty()) {
for (int i = 0; i < this.interceptors.size(); i++) {
Object interceptor = this.interceptors.get(i);
if (interceptor == null) {
throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
}
this.adaptedInterceptors.add(adaptInterceptor(interceptor));
}
}
}
/**
* 使给定的拦截器对象适应{@link HandlerInterceptor}接口。
* <p>默认情况下,支持的拦截器类型为{@link HandlerInterceptor}
*和{@link WebRequestInterceptor}。每个给定的{@link WebRequestInterceptor}
*将包装在{@link WebRequestHandlerInterceptorAdapter}中。
*可以在子类中覆盖。
*
* @param interceptor 指定的拦截器对象
* @return 包装为HandlerInterceptor的拦截器
* @see org.springframework.web.servlet.HandlerInterceptor
* @see org.springframework.web.context.request.WebRequestInterceptor
* @see WebRequestHandlerInterceptorAdapter
*/
protected HandlerInterceptor adaptInterceptor(Object interceptor) {
if (interceptor instanceof HandlerInterceptor) {
return (HandlerInterceptor) interceptor;
} else if (interceptor instanceof WebRequestInterceptor) {
return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
} else {
throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());
}
}
/**
* 将调整后的拦截器返回为Handlerchiptor数组。
*
* @return the array of {@link HandlerInterceptor HandlerInterceptors}, or {@code null} if none
*/
@Nullable
protected final HandlerInterceptor[] getAdaptedInterceptors() {
return (!this.adaptedInterceptors.isEmpty() ?
this.adaptedInterceptors.toArray(new HandlerInterceptor[0]) : null);
}
/**
* 将所有配置的{@link MappedInterceptor MappedInterceptors}作为数组返回
*
* @return the array of {@link MappedInterceptor MappedInterceptors}, or {@code null} if none
*/
@Nullable
protected final MappedInterceptor[] getMappedInterceptors() {
List<MappedInterceptor> mappedInterceptors = new ArrayList<>(this.adaptedInterceptors.size());
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
mappedInterceptors.add((MappedInterceptor) interceptor);
}
}
return (!mappedInterceptors.isEmpty() ? mappedInterceptors.toArray(new MappedInterceptor[0]) : null);
}
/**
*
* 查找给定请求的处理程序,返回到默认值
* *如果找不到特定的处理程序。
*
* @param request current HTTP request
* @return the corresponding handler instance, or the default handler
* @see #getHandlerInternal
*/
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
} else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}
if (hasCorsConfigurationSource(handler)) {
CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
/**
* 查找给定请求的处理程序,如果没有,则返回{@code null}
* 找到具体的一个。此方法由{@link#getHandler}调用;
* {@code null}返回值将导致默认处理程序(如果已设置)。
* <p>在CORS飞行前请求时,此方法应返回一个匹配项,而不是
* 飞行前请求,但基于URL的预期实际请求
* 路径,来自“访问控制请求方法”头的HTTP方法,以及
* “访问控制请求头”头中的头,因此允许
* 通过{@link\getCorsConfiguration(Object,HttpServletRequest)}获得的CORS配置,
* <p>注意:此方法还可能返回预先构建的{@link HandlerExecutionChain},
* 将处理程序对象与动态确定的侦听器组合。
* 静态指定的拦截器将合并到这样的现有链中。.
*
* @param request current HTTP request
* @return the corresponding handler instance, or {@code null} if none found
* @throws Exception if there is an internal error
*/
@Nullable
protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;
/**
* 查找给定请求的处理程序,如果没有,则返回{@code null}
* 找到具体的一个。此方法由{@link#getHandler}调用;
* {@code null}返回值将导致默认处理程序(如果已设置)。
* 在CORS飞行前请求时,此方法应返回一个匹配项,而不是
* 飞行前请求,但基于URL的预期实际请求
* 路径,来自“访问控制请求方法”头的HTTP方法,以及
* “访问控制请求头”头中的头,因此允许
* 通过{@link\getCorsConfiguration(Object,HttpServletRequest)}获得的CORS配置,
* 注意:此方法还可能返回预先构建的{@link HandlerExecutionChain},
* 将处理程序对象与动态确定的侦听器组合。
* 静态指定的拦截器将合并到这样的现有链中。.
*
* @param handler the resolved handler instance (never {@code null})
* @param request current HTTP request
* @return the HandlerExecutionChain (never {@code null})
* @see #getAdaptedInterceptors()
*/
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
/**
* Return {@code true} if there is a {@link CorsConfigurationSource} for this handler.
*
* @since 5.2
*/
protected boolean hasCorsConfigurationSource(Object handler) {
if (handler instanceof HandlerExecutionChain) {
handler = ((HandlerExecutionChain) handler).getHandler();
}
return (handler instanceof CorsConfigurationSource || this.corsConfigurationSource != null);
}
/**
* 检索给定处理程序的CORS配置。
*
* @param handler the handler to check (never {@code null}).
* @param request the current request.
* @return the CORS configuration for the handler, or {@code null} if none
* @since 4.2
*/
@Nullable
protected CorsConfiguration getCorsConfiguration(Object handler, HttpServletRequest request) {
Object resolvedHandler = handler;
if (handler instanceof HandlerExecutionChain) {
resolvedHandler = ((HandlerExecutionChain) handler).getHandler();
}
if (resolvedHandler instanceof CorsConfigurationSource) {
return ((CorsConfigurationSource) resolvedHandler).getCorsConfiguration(request);
}
return null;
}
/**
* 更新与CORS相关处理的HandlerExecutionChain。
* *<p>对于飞行前请求,默认实现将替换选定的
* *一个简单的HttpRequestHandler调用配置的
* *{@link#setCorsProcessor}。
* *<p>对于实际请求,默认实现插入
* *进行CORS相关检查并添加CORS标题的HandlerInterceptor
*
* @param request the current request
* @param chain the handler chain
* @param config the applicable CORS configuration (possibly {@code null})
* @since 4.2
*/
protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
HandlerExecutionChain chain, @Nullable CorsConfiguration config) {
if (CorsUtils.isPreFlightRequest(request)) {
HandlerInterceptor[] interceptors = chain.getInterceptors();
chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
} else {
chain.addInterceptor(0, new CorsInterceptor(config));
}
return chain;
}
private class PreFlightHandler implements HttpRequestHandler, CorsConfigurationSource {
@Nullable
private final CorsConfiguration config;
public PreFlightHandler(@Nullable CorsConfiguration config) {
this.config = config;
}
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
corsProcessor.processRequest(this.config, request, response);
}
@Override
@Nullable
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
return this.config;
}
}
private class CorsInterceptor extends HandlerInterceptorAdapter implements CorsConfigurationSource {
@Nullable
private final CorsConfiguration config;
public CorsInterceptor(@Nullable CorsConfiguration config) {
this.config = config;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return corsProcessor.processRequest(this.config, request, response);
}
@Override
@Nullable
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
return this.config;
}
}
}
springmvc组件HandleMapping源码-AbstractHandlerMapping
最新推荐文章于 2023-09-28 09:47:36 发布