对于springmvc框架的基本执行逻辑包含以下几步
- 查找能够处理http请求的Handler(通过HandlerMapping来查找)
- 查询能处理Handler的适配器HandlerAdapter
- 执行HandlerAdapter得到ModelAndView
- 根据ModelAndView得到对应的View
- 执行View的渲染方法进行客户端的响应
那么本章节主要讲解其查找Handler的过程。
在DispatcherServlet初始化的时候会通过以下代码来初始化HandlerMappings
public class DispatcherServlet extends FrameworkServlet {
/**
* Initialize the HandlerMappings used by this class.
* <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
* we default to BeanNameUrlHandlerMapping.
*/
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
//判断是否查找所有的HandlerMappings,默认为true
if (this.detectAllHandlerMappings) {
// 从ApplicationContext(包括祖先祖先ApplicationContext)中查找所有HandlerMapping类型的Bean
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// 对查找到的HandlerMapping进行排序
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
//直接从当前的ApplicationContext获取名为handlerMapping,类型为HandlerMapping的bean
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// 如果通过上面步骤没找到HandlerMapping则使用DispatcherServlet.properties中默认配置的HandlerMapping
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
for (HandlerMapping mapping : this.handlerMappings) {
if (mapping.usesPathPatterns()) {
this.parseRequestPath = true;
break;
}
}
}
}
在spring-webmvc包中的DispatcherServlet.properties中默认配置了以下的HandlerMapping
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
org.springframework.web.servlet.function.support.RouterFunctionMapping
spring-webmvc框架在处理请求时通过以下方法来查找Handler,当然,实际是返回的一个包含了Handler的HandlerExecutionChain
/**
* Return the HandlerExecutionChain for this request.
* <p>Tries all handler mappings in order.
* @param request current HTTP request
* @return the HandlerExecutionChain, or {@code null} if no handler could be found
*/
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
从上可见,HandlerMapping的具体实现与Handler的查找息息相关,在讲解HandlerMapping的具体实现前,我们先聊聊会被具体实现继承的抽象类AbstractHandlerMapping
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
implements HandlerMapping, Ordered, BeanNameAware {
@Nullable
private Object defaultHandler;
@Nullable
private PathPatternParser patternParser;
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;
/**
* Initializes the interceptors.
* @see #extendInterceptors(java.util.List)
* @see #initInterceptors()
*/
@Override
protected void initApplicationContext() throws BeansException {
extendInterceptors(this.interceptors);
detectMappedInterceptors(this.adaptedInterceptors);
initInterceptors();
}
/**
* Look up a handler for the given request, falling back to the default
* handler if no specific one is found.
* @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);
}
//生成Handler的调用链(封装了该Handler所需的拦截器)
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());
}
//hasCorsConfigurationSource:如果实际的handler是CorsConfigurationSource类型,
//或者corsConfigurationSource不为空,这返回true
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
//获取该Handler的跨域配置
CorsConfiguration config = getCorsConfiguration(handler, request);
if (getCorsConfigurationSource() != null) {
CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
config = (globalConfig != null ? globalConfig.combine(config) : config);
}
if (config != null) {
config.validateAllowCredentials();
}
//给executionChain 添加CorsInterceptor拦截器
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
//供具体的子类来实现Handler的查找
@Nullable
protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
//遍历所有的HandlerInterceptor,如果是实现类MappedInterceptor 则判断是否匹配当前的请求,
//如果匹配则将持有的HandlerInterceptor实例添加到拦截器链中;如果不是MappedInterceptor ,
//则直接加入到拦截器链中
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(request)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
HandlerExecutionChain chain, @Nullable CorsConfiguration config) {
if (CorsUtils.isPreFlightRequest(request)) {
HandlerInterceptor[] interceptors = chain.getInterceptors();
return new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
}
else {
chain.addInterceptor(0, new CorsInterceptor(config));
return chain;
}
}
}
AbstractHandlerMapping中initApplicationContext方法的目的是为了初始化Handler的拦截器(HandlerInterceptor),其会得到ApplicationContext中所有MappedInterceptor类型的Bean(MappedInterceptor是HandlerInterceptor接口的实现类)。MappedInterceptor实例内部持有HandlerInterceptor类型的实例,通过MappedInterceptor的matches方法可以判断某请求是否需要使用该拦截器。
其中的getHandlerInternal方法供子类去实现,不同的子类其查找的策略会不一样,其得到的Handler的类型也不同。
1,BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping将URL映射到名称以斜杠(“/”)开头的bean。该种查找方式现在用的应该很少了,所以这里就简单的说说。
在BeanNameUrlHandlerMapping初始化的过程中首先会获取所有名称以斜杠(“/”)开头的bean,当请求到来时再与请求的路径进行匹配,当匹配成功则该bean就是对应的Handler。由于该种查找方式用的不多,这里就不再多缀诉了。
2,RequestMappingHandlerMapping
该对象是目前使用最多的,所以我们先来看看其初始化的过程。其初始化的过程从RequestMappingHandlerMapping的initApplicationContext方法开始
- 首先执行继承自AbstractHandlerMapping的initApplicationContext方法。
该方法的目的是为了初始化Handler的拦截器(HandlerInterceptor),其会得到ApplicationContext中所有MappedInterceptor类型的Bean(MappedInterceptor是HandlerInterceptor接口的实现类)。MappedInterceptor实例内部持有HandlerInterceptor类型的实例,通过MappedInterceptor的matches方法可以判断某请求是否需要使用该拦截器。
2.执行RequestMappingHandlerMapping的afterPropertiesSet方法
执行父类AbstractHandlerMethodMapping的afterPropertiesSet方法
执行AbstractHandlerMethodMapping的initHandlerMethods方法
initHandlerMethods的整体目的是扫描ApplicationContext中的bean,检测并注册handler方法
-> 首先从ApplicationContext中所以Object类型Bean的名称,然后过滤掉“scopedTarget.”开头的
-> 遍历所有的名称并从ApplicationContext中获取Bean的Class类型
-> 判断得到的Class是否为Handler(判断是否有Controller和RequestMapping注解)
-> 解析Class,得到包含RequestMapping注解的方法
-> 将方法封装到HandlerMethod,并将其注册到MappingRegistry中
当请求到来时,将会从MappingRegistry中查找最匹配的Handler,此时的Handler本身是个Method。
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
/**
* Look up a handler method for the given request.
*/
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = initLookupPath(request);
this.mappingRegistry.acquireReadLock();
try {
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
/**
* Look up the best-matching handler method for the current request.
* If multiple matches are found, the best match is selected.
* @param lookupPath mapping lookup path within the current servlet mapping
* @param request the current request
* @return the best-matching handler method, or {@code null} if no match
* @see #handleMatch(Object, String, HttpServletRequest)
* @see #handleNoMatch(Set, String, HttpServletRequest)
*/
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
bestMatch = matches.get(0);
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
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();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
}
}
}