1.BeanNameUrlHandlerMapping作用
BeanNameUrlHandlerMapping作用是将以/开头的beanName认为是请求url,通过访问url找到对应的bean,执行其内部的处理方法
使用示例:创建类继承Controller接口并添加@Controller("/controller")注解,@Controller注解中的value必须以/开头,配置类及测试代码参考前文SpringMVC源码分析(一)--基本组件
@Controller("/test02")
public class Controller02 implements org.springframework.web.servlet.mvc.Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
response.getWriter().print("hello test02");
return null;
}
}
浏览器访问http://127.0.0.1:8080/test02,页面即可响应hello test02文本
2.BeanNameUrlHandlerMapping注册处理器
BeanNameUrlHandlerMapping间接实现了ApplicationContextAware接口,初始化时会调用ApplicationObjectSupport#setApplicationContext
public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
if (context == null && !this.isContextRequired()) {
this.applicationContext = null;
this.messageSourceAccessor = null;
} else if (this.applicationContext == null) {
if (!this.requiredContextClass().isInstance(context)) {
throw new ApplicationContextException("Invalid application context: needs to be of type [" + this.requiredContextClass().getName() + "]");
}
this.applicationContext = context;
this.messageSourceAccessor = new MessageSourceAccessor(context);
// 初始化
this.initApplicationContext(context);
} else if (this.applicationContext != context) {
throw new ApplicationContextException("Cannot reinitialize with different application context: current one is [" + this.applicationContext + "], passed-in one is [" + context + "]");
}
}
protected void initApplicationContext(ApplicationContext context) throws BeansException {
// 调用子类的初始化方法
this.initApplicationContext();
}
protected void initApplicationContext() throws BeansException {}
initApplicationContext调用的是AbstractDetectingUrlHandlerMapping#initApplicationContext
public void initApplicationContext() throws ApplicationContextException {
// 1.调用父类AbstractHandlerMapping#initApplicationContext
super.initApplicationContext();
// 2.检测处理器方法
detectHandlers();
}
在AbstractDetectingUrlHandlerMapping#initApplicationContext中首先调用父类的initApplicationContext,目的是初始化interceptors,这部分可以通过子类继承扩展
protected void initApplicationContext() throws BeansException {
extendInterceptors(this.interceptors);
detectMappedInterceptors(this.adaptedInterceptors);
initInterceptors();
}
protected void extendInterceptors(List<Object> interceptors) {}
protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
// 查找容器中的MappedInterceptor,加入到adaptedInterceptors集合中
mappedInterceptors.addAll(BeanFactoryUtils.beansOfTypeIncludingAncestors(
obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}
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");
}
// 将interceptor适配成HandlerInterceptor,加入到adaptedInterceptors集合中
this.adaptedInterceptors.add(adaptInterceptor(interceptor));
}
}
}
添加完HandlerInterceptor之后,调用detectHandlers,寻找处理器方法
protected void detectHandlers() throws BeansException {
ApplicationContext applicationContext = obtainApplicationContext();
// detectHandlersInAncestorContexts表示是否在父容器中寻找
// true表示在父容器和当前容器中查找所有bean,false表示只查找当前容器中的bean
String[] beanNames = (this.detectHandlersInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
applicationContext.getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
// 检查beanName是否满足,抽象方法由BeanNameUrlHandlerMapping实现
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
// 如果找到了,注册处理器
registerHandler(urls, beanName);
}
}
if ((logger.isDebugEnabled() && !getHandlerMap().isEmpty()) || logger.isTraceEnabled()) {
logger.debug("Detected " + getHandlerMap().size() + " mappings in " + formatMappingName());
}
}
protected abstract String[] determineUrlsForHandler(String beanName);
determineUrlsForHandler用于判断beanName是否以/开头,如果满足条件则会认为找到了控制器类
protected String[] determineUrlsForHandler(String beanName) {
List<String> urls = new ArrayList<>();
// 如果beanName以/开头就满足条件
if (beanName.startsWith("/")) {
urls.add(beanName);
}
// 或者beanName的别名以/开头也满足条件
String[] aliases = obtainApplicationContext().getAliases(beanName);
for (String alias : aliases) {
if (alias.startsWith("/")) {
urls.add(alias);
}
}
return StringUtils.toStringArray(urls);
}
探测到控制器类之后就需要注册其中的请求处理方法,即调用AbstractUrlHandlerMapping#registerHandler
protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
Assert.notNull(urlPaths, "URL path array must not be null");
for (String urlPath : urlPaths) {
registerHandler(urlPath, beanName);
}
}
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;
// 如果handler的类型是string,并且不是懒加载的,从Spring容器中根据类名获取处理器bean
if (!this.lazyInitHandlers && handler instanceof String) {
String handlerName = (String) handler;
ApplicationContext applicationContext = obtainApplicationContext();
if (applicationContext.isSingleton(handlerName)) {
resolvedHandler = applicationContext.getBean(handlerName);
}
}
// 校验是否有重复路径
Object mappedHandler = this.handlerMap.get(urlPath);
if (mappedHandler != null) {
if (mappedHandler != resolvedHandler) {
throw new IllegalStateException(
"Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
}
}
else {
// 1.如果路径就是/,则设置为rootHandler
if (urlPath.equals("/")) {
if (logger.isTraceEnabled()) {
logger.trace("Root mapping to " + getHandlerDescription(handler));
}
setRootHandler(resolvedHandler);
}
// 2.如果路径就是/*,则设置为defaultHandler
else if (urlPath.equals("/*")) {
if (logger.isTraceEnabled()) {
logger.trace("Default mapping to " + getHandlerDescription(handler));
}
setDefaultHandler(resolvedHandler);
}
// 3.否则将路径-控制器类添加到handlerMap中
else {
this.handlerMap.put(urlPath, resolvedHandler);
if (logger.isTraceEnabled()) {
logger.trace("Mapped [" + urlPath + "] onto " + getHandlerDescription(handler));
}
}
}
}
至此BeanNameUrlHandlerMapping初始化完成
3.BeanNameUrlHandlerMapping获取处理器
当DispatcherServlet接收到请求时,与前文所述RequestMappingHandlerMapping一样,会在doDispatch方法中调用getHandler遍历每个HanderMapping去获取对应的处理器,源码见DispatcherServlet#getHandler
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
// 遍历每个HanderMapping
for (HandlerMapping mapping : this.handlerMappings) {
// 获取处理器对象
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
假设请求是http://127.0.0.1:8080/test02,则通过BeanNameUrlHandlerMapping能够匹配到对应的处理器方法
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 抽象方法,由具体的实现类处理,这里调用AbstractUrlHandlerMapping#getHandlerInternal
Object handler = getHandlerInternal(request);
if (handler == null) {
// 如果没有找到,则获取默认处理器,即匹配上文中注册/*的处理器
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// handler如果是string,则根据类名从容器中获取bean
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 封装成HandlerExecutionChain,其中包含Handler及HandlerInterceptor
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) || CorsUtils.isPreFlightRequest(request)) {
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;
}
AbstractUrlHandlerMapping#getHandlerInternal源码如下:
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
// 获取请求的路径
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
// 查找Handler
Object handler = lookupHandler(lookupPath, request);
// 如果没有找到Handler
if (handler == null) {
Object rawHandler = null;
// 如果路径就是/,则返回rootHandler
if (StringUtils.matchesCharacter(lookupPath, '/')) {
rawHandler = getRootHandler();
}
// 仍然为null,则返回defaultHandler
if (rawHandler == null) {
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
// 如果是string类型,则从容器中根据类名获取bean
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = obtainApplicationContext().getBean(handlerName);
}
validateHandler(rawHandler, request);
// 封装成HandlerExecutionChain
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
return handler;
}
protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
String pathWithinMapping, @Nullable Map<String, String> uriTemplateVariables) {
HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));
if (!CollectionUtils.isEmpty(uriTemplateVariables)) {
chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));
}
return chain;
}
根据路径查找方法处理器的核心逻辑如下:
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
// 直接根据url从handlerMap中查找
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
// 如果查找到了直接返回
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
return buildPathExposingHandler(handler, urlPath, urlPath, null);
}
// 通过正则匹配查找最符合的处理器
// 添加路径表达式到matchingPatterns
List<String> matchingPatterns = new ArrayList<>();
for (String registeredPattern : this.handlerMap.keySet()) {
if (getPathMatcher().match(registeredPattern, urlPath)) {
matchingPatterns.add(registeredPattern);
}
else if (useTrailingSlashMatch()) {
if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
matchingPatterns.add(registeredPattern + "/");
}
}
}
String bestMatch = null;
// 将路径按某种规则排序
Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
if (!matchingPatterns.isEmpty()) {
matchingPatterns.sort(patternComparator);
if (logger.isTraceEnabled() && matchingPatterns.size() > 1) {
logger.trace("Matching patterns " + matchingPatterns);
}
// 获取最佳匹配的路径
bestMatch = matchingPatterns.get(0);
}
if (bestMatch != null) {
// 获取最佳匹配的Handler
handler = this.handlerMap.get(bestMatch);
if (handler == null) {
if (bestMatch.endsWith("/")) {
handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));
}
if (handler == null) {
throw new IllegalStateException(
"Could not find handler for best pattern match [" + bestMatch + "]");
}
}
// 如果是string,从Spring容器中根据类名获取bean
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);
Map<String, String> uriTemplateVariables = new LinkedHashMap<>();
for (String matchingPattern : matchingPatterns) {
if (patternComparator.compare(bestMatch, matchingPattern) == 0) {
Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
uriTemplateVariables.putAll(decodedVars);
}
}
if (logger.isTraceEnabled() && uriTemplateVariables.size() > 0) {
logger.trace("URI variables " + uriTemplateVariables);
}
return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);
}
return null;
}
最后将HandlerExecutionChain对象交给HandlerAdapter去执行,这里BeanNameUrlHandlerMapping匹配的是SimpleControllerHandlerAdapter,它会执行handle方法调用自定义控制器中重写的handle方法处理请求
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
// 是否支持此handler,显然是支持的,因为我们定义的/controller实现了mvc包中的Controller接口
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 调用我们控制器中重写的handle方法处理请求
return ((Controller) handler).handleRequest(request, response);
}
// 省略其他代码...
}
请求的执行过程将在HandlerAdapter篇章中详述