1.源码版本
spring-mvc 4.3.9
2.回顾
通过源码分析一可以看到 , 在DispatcherServlet的doDispatch方法中,有一个很重要的方法,就是通过request获取
当前请求的handler , 这个handler就是我们请求的那个方法的封装。 这里主要说一下,spring mvc是如何对Controller
进行初始化,以及http请求过来之后,是怎么通过通过请求URL找到相应的请求的。
3.AbstractHandlerMethodMapping
主要是看这个类,该类里面对Controller的方法进行的初始化,以及映射关系的查找
public void afterPropertiesSet() { // 加载完该BEAN之后,调用initHandlerMethods方法。进行初始化 initHandlerMethods(); } protected void initHandlerMethods() { if (logger.isDebugEnabled()) { logger.debug("Looking for request mappings in application context: " + getApplicationContext()); } // 获取spring容器里面所有的beanName String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); // 遍历beanName for (String beanName : beanNames) { // 如果是scopedTarget.这个开头的bean, 则不做处理。 if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { Class<?> beanType = null; try { // 获取bean类型 beanType = getApplicationContext().getType(beanName); } catch (Throwable ex) { // An unresolvable bean type, probably from a lazy bean - let's ignore it. if (logger.isDebugEnabled()) { logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex); } } // 如果beanType 不为空,并且isHandler为true if (beanType != null && isHandler(beanType)) { // 对方法进行处理 detectHandlerMethods(beanName); } } } handlerMethodsInitialized(getHandlerMethods()); } |
从上面可以看到,在决定是否要处理该BEAN时,有个isHandler 方法 , 该方法主要就是判断这个类上面是否有@Controller获取@RequestMapping注解
@Override protected boolean isHandler(Class<?> beanType) { return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); } |
detectHandlerMethods主要是将这个类所有带有@RequestMappering的方法收集起来、
protected void detectHandlerMethods(final Object handler) { // 判断handler是对象还是字符串,如果是字符串则从容器里面去拿 Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass()); final Class<?> userType = ClassUtils.getUserClass(handlerType); // 筛选方法 Map<Method, T> methods = MethodIntrospector.selectMethods(userType, new MethodIntrospector.MetadataLookup<T>() { @Override public T inspect(Method method) { try { // 主要是看这个方法 return getMappingForMethod(method, userType); } catch (Throwable ex) { throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, ex); } } }); if (logger.isDebugEnabled()) { logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods); } // 遍历所有带有@RequestMapping的方法 , 以method为key , requestMappingInfo为value for (Map.Entry<Method, T> entry : methods.entrySet()) { Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType); T mapping = entry.getValue(); // 注册方法,将方法映射信息放入内存 registerHandlerMethod(handler, invocableMethod, mapping); } } |
@Override protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { // 创建RequestMappingInfo RequestMappingInfo info = createRequestMappingInfo(method); if (info != null) { RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType); if (typeInfo != null) { info = typeInfo.combine(info); } } return info; } private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) { // 获取该方法中的RequestMapping 信息 RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class); RequestCondition<?> condition = (element instanceof Class ? getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element)); // 如果能找到RequestMapping 那么则构建RequestMappingInfo实体信息返回,没有则返回空 return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null); } |
通过上面的源码分析 我们可以看到detectHandlerMethods调用到最后,是调用了registerHandlerMethod
protected void registerHandlerMethod(Object handler, Method method, T mapping) { this.mappingRegistry.register(mapping, handler, method); } |
MappingRegistry 是 AbstractHandlerMethodMapping的一个内部类,上面是通过this.mappingRegistry这个属性
调用该内部类中的register方法,将该方法注册到映射注册中心去,
private final Map<T, MappingRegistration<T>> registry = new HashMap<T, MappingRegistration<T>>(); // requestMappingInfo 和HandlerMethod的对应关系 private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<T, HandlerMethod>(); // url 和requestMappingInfo的对应关系 private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<String, T>(); // name和HandlerMethod的关系 private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<String, List<HandlerMethod>>(); // 方法和跨域信息的映射 private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<HandlerMethod, CorsConfiguration>(); private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public void register(T mapping, Object handler, Method method) { // 上锁因为registry , mappingLookup , urlLookup 这两个LinkedHashMap是非线程安全的 this.readWriteLock.writeLock().lock(); try { 构建handlerMethod HandlerMethod handlerMethod = createHandlerMethod(handler, method); assertUniqueMethodMapping(handlerMethod, mapping); if (logger.isInfoEnabled()) { logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod); } // 将requestMappingInfo为键,handlerMethod为value,放入linkedHashMap this.mappingLookup.put(mapping, handlerMethod); // 获取该方法上的url地址, List<String> directUrls = getDirectUrls(mapping); for (String url : directUrls) { // 将请求映射的URL放入LinkedMultiValueMap , 一个key对应多个value // 防止出现比如同一个URL,有一个是GET 请求,一个是给POST的请求的 // 那样就会出现同一个url对应多个RequestMappingInfo的情况 this.urlLookup.add(url, mapping); } //spring mvc 4.x以后,可以通过配置name属性来方位该方法,次数就是为了完成这个操作 String name = null; if (getNamingStrategy() != null) { // name = getNamingStrategy().getName(handlerMethod, mapping); addMappingName(name, handlerMethod); } // 处理跨域请求的注解,如果某个method上用了@CrossOrigin这个注解 CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping); if (corsConfig != null) { // 如果不为空,那么将这个方法对应的跨域 信息放入map中 this.corsLookup.put(handlerMethod, corsConfig); } this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name)); } finally { this.readWriteLock.writeLock().unlock(); } } protected HandlerMethod createHandlerMethod(Object handler, Method method) { HandlerMethod handlerMethod; if (handler instanceof String) { String beanName = (String) handler; handlerMethod = new HandlerMethod(beanName, getApplicationContext().getAutowireCapableBeanFactory(), method); } else { handlerMethod = new HandlerMethod(handler, method); } // 这个HandlerMethod里面包含了大量的信息,bean, beanFactory, beanType,method ,parameters 等等 return handlerMethod; } |
DispatcherServlet的getHandler
最终我们回调dispatcherServlet这个类里面来,这个过滤器里面通过request获取Handler
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { for (HandlerMapping hm : this.handlerMappings) { if (logger.isTraceEnabled()) { logger.trace( "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); } // 获取Handler执行链 HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; } |
直接看gethandler方法
@Override public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { // 通过这个方法获取Handler,主要看这个 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 = getApplicationContext().getBean(handlerName); } // 获取handler的执行链,主要是把拦截器的执行也构建在了这个方法里面 HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); if (CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; } |
getHandlerInternal这个方法是个抽象方法,具体实现在AbstractHandlerMethodMapping
@Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { //获取请求路径 String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); if (logger.isDebugEnabled()) { logger.debug("Looking up handler method for path " + lookupPath); } // 上锁因为这个类里面的map很多是非线程安全的 this.mappingRegistry.acquireReadLock(); try { // 重点在这里 HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); if (logger.isDebugEnabled()) { if (handlerMethod != null) { logger.debug("Returning handler method [" + handlerMethod + "]"); } else { logger.debug("Did not find handler method for [" + lookupPath + "]"); } } return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } finally { this.mappingRegistry.releaseReadLock(); } } |
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List<Match> matches = new ArrayList<Match>(); // 通过URL,从对应的映射map里面获取requestMappingInfo List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); if (directPathMatches != null) { // 该方法会对requestMappingInfo中的各种条件做匹配,如果匹配对了,则放入matches addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { // No choice but to go through all mappings... // 没有匹配到,则遍历所有的requestMappingInfo ,期望能找到一个 addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request); } if (!matches.isEmpty()) { // 比较找到的matches , 通过requestMappingInfo中的compareTo进行排序 Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); Collections.sort(matches, comparator); if (logger.isTraceEnabled()) { logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches); } // 获取匹配度最高的 Match bestMatch = matches.get(0); if (matches.size() > 1) { 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(); throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" + m1 + ", " + m2 + "}"); } } // 返回找到的handler handleMatch(bestMatch.mapping, lookupPath, request); return bestMatch.handlerMethod; } else { // 返回NoMatch ,匹配失败 return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request); } } |