前言:
- 本文源码基于
spring-framework-5.3.10
。 mvc
是spring
源码中的一个子模块!
一、RequestMappingHandlerMapping解析映射简单介绍
- @RequestMapping通过
RequestMappingHandlerMapping
进行解析! - HandlerMapping是一个根据URL映射到Handler的方法。
RequestMappingHandlerMapping
是HandlerMapping的一个子类!- RequestMappingHandlerMapping他的父类有InitializingBean,所有在spring启动实例化的时候会调用afterPropertiesSet()方法。解析逻辑就在这里。
RequestMappingHandlerMapping
有俩个过程:解析、映射
二、@RequestMapping解析源码流程
- 容器加载,调用
RequestMappingHandlerMapping
的afterPropertiesSet
()。 - 调用父类的
afterPropertiesSet()
方法。 - 调用initHandlerMethods()方法。
- 循环每一个Bean,看方法上有@RequestMapping或者@Controller的Bean。
- 解析
HandlerMethods
,进行封装RequestMappingInfo。 - 将封装好的
RequestMappingInfo
存起来:key为路径,值为mapping(RequestMappingInfo)
三、@RequestMapping映射源码流程
- 请求进来,调用
getHandler
方法。 - 获取当前请求对应的
HandlerMethod
。 - 通过
UrlPathHelper
对象,用于来解析从们的request中解析出请求映射路径。 - 更具路径去
pathLookup
中找。 - 上面没找到,从所有的里面找有通配符的。
- 找到多个进行排序,优先级:? > * > {} >** 。
- 不为空拿到第一个返回。
- 如果为空获取默认的。默认还是空的,直接返回null。
- 封装拦截器,返回。
四、@RequestMapping解析源码
- /**
- * 解析的开始位置。
- * 由于实现了InitializingBean,初始化Bean的时候调用这个方法。
- * 源码位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.afterPropertiesSet()
- */
- public void afterPropertiesSet() {
-
- this.config = new RequestMappingInfo.BuilderConfiguration();
- this.config.setTrailingSlashMatch(useTrailingSlashMatch()); // 尾部斜杠
- this.config.setContentNegotiationManager(getContentNegotiationManager());
-
- if (getPatternParser() != null) {
- this.config.setPatternParser(getPatternParser());
- Assert.isTrue(!this.useSuffixPatternMatch && !this.useRegisteredSuffixPatternMatch,
- "Suffix pattern matching not supported with PathPatternParser.");
- }
- else {
- this.config.setSuffixPatternMatch(useSuffixPatternMatch());
- this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
- this.config.setPathMatcher(getPathMatcher());
- }
-
- // 调用父类的afterPropertiesSet方法
- super.afterPropertiesSet();
- }
-
- /**
- * 父类的afterPropertiesSet方法。
- * 源码位置:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.afterPropertiesSet()
- */
- public void afterPropertiesSet() {
- initHandlerMethods();
- }
-
- /**
- * 解析@RequestMapping方法
- * 源码位置:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods()
- */
- protected void initHandlerMethods() {
- // 获得所有候选beanName—— 当前容器所有的beanName
- for (String beanName : getCandidateBeanNames()) {
- // BeanName不是scopedTarget.开头的
- if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
- // *处理候选bean——即解析@RequestMapping和映射路径
- processCandidateBean(beanName);
- }
- }
- // 解析完所有@RequestMapping的时候调用
- handlerMethodsInitialized(getHandlerMethods());
- }
-
- /**
- * 处理候选bean——即解析@RequestMapping和映射路径
- * 源码位置:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.processCandidateBean(String)
- */
- protected void processCandidateBean(String beanName) {
- Class<?> beanType = null;
- try {
- // 得到当前BeanName得到这个Bean的类型
- beanType = obtainApplicationContext().getType(beanName);
- }
- catch (Throwable ex) {
- // An unresolvable bean type, probably from a lazy bean - let's ignore it.
- if (logger.isTraceEnabled()) {
- logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
- }
- }
- // 这一步判断是关键:是否有Controller 或 RequestMapping注解
- if (beanType != null && isHandler(beanType)) {
- // 解析HandlerMethods
- detectHandlerMethods(beanName);
- }
- }
-
- /**
- * 解析HandlerMethods
- * 源码位置:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.detectHandlerMethods(Object)
- */
- protected void detectHandlerMethods(Object handler) {
- Class<?> handlerType = (handler instanceof String ?
- obtainApplicationContext().getType((String) handler) : handler.getClass());
-
- if (handlerType != null) {
- Class<?> userType = ClassUtils.getUserClass(handlerType);
- // 循环所有方法
- Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
- (MethodIntrospector.MetadataLookup<T>) method -> {
- try {
- // 根据Method得到Mapping映射
- return getMappingForMethod(method, userType);
- }
- catch (Throwable ex) {
- throw new IllegalStateException("Invalid mapping on handler class [" +
- userType.getName() + "]: " + method, ex);
- }
- });
- if (logger.isTraceEnabled()) {
- logger.trace(formatMappings(userType, methods));
- }
- else if (mappingsLogger.isDebugEnabled()) {
- mappingsLogger.debug(formatMappings(userType, methods));
- }
- // 遍历每一个方法,这里是所有Bean的所有方法
- methods.forEach((method, mapping) -> {
- Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
- // pathLookup放入:key为路径,值为mapping(RequestMappingInfo)
- registerHandlerMethod(handler, invocableMethod, mapping);
- });
- }
- }
-
- /**
- * 根据Method得到Mapping映射
- * 源码位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.getMappingForMethod(Method, Class<?>)
- */
- protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
- // 如果方法上面有@RequestMapping:解析出RequestMappingInfo
- // RequestMappingInfo 是用来在请求的时候做匹对的
- RequestMappingInfo info = createRequestMappingInfo(method);
- if (info != null) {
- // 如果方法上面有@RequestMapping,看看类上面是不是有@RequestMapping
- RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
- // 类上面也有@RequestMapping 那就合并
- // 比如 类:/user 方法:/info 合并为 /user/info
- if (typeInfo != null) {
- info = typeInfo.combine(info);
- }
-
- // 合并前缀 5.1新增 默认null
- // 可通过 WebMvcConfigurer#configurePathMatch 进行定制
- String prefix = getPathPrefix(handlerType);
- if (prefix != null) {
- info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
- }
- }
- return info;
- }
-
- /**
- * 创建请求映射信息的外部逻辑
- * 源码位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.createRequestMappingInfo(AnnotatedElement)
- */
- 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);
- }
-
- /**
- * 创建请求映射信息的内部逻辑
- * 源码位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.createRequestMappingInfo(RequestMapping, RequestCondition<?>)
- */
- protected RequestMappingInfo createRequestMappingInfo(
- RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {
- // 将@RequestMapping注解属性的值构建成一个 RequestMappingInfo
- RequestMappingInfo.Builder builder = RequestMappingInfo
- //构建路径
- .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
- //构建方法(get还是post等)
- .methods(requestMapping.method())
- //参数 对应http request parameter
- .params(requestMapping.params())
- //头部
- .headers(requestMapping.headers())
- //request的提交内容类型content type,如application/json, text/html
- .consumes(requestMapping.consumes())
- //指定返回的内容类型的content type,仅当request请求头中的(Accept)类型中包含该指定类型才返回
- .produces(requestMapping.produces())
- .mappingName(requestMapping.name());
- if (customCondition != null) {
- builder.customCondition(customCondition);
- }
- // 构造RequestMappingInfo:将上面的属性构建成一个个的RequestCondition对象方便在请求的时候组合匹对
- return builder.options(this.config).build();
- }
-
- /**
- * 得到所有的方法
- * 源码位置:org.springframework.core.MethodIntrospector.selectMethods(Class<?>, MetadataLookup<T>)
- */
- public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
- final Map<Method, T> methodMap = new LinkedHashMap<>();
- Set<Class<?>> handlerTypes = new LinkedHashSet<>();
- Class<?> specificHandlerType = null;
- //获取原始的class对象
- if (!Proxy.isProxyClass(targetType)) {
- specificHandlerType = ClassUtils.getUserClass(targetType);
- handlerTypes.add(specificHandlerType);
- }
- //获取class的接口
- handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));
- //循环我们的class集合
- for (Class<?> currentHandlerType : handlerTypes) {
- final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
-
- ReflectionUtils.doWithMethods(currentHandlerType, method -> {
- //获取具体的方法对象
- Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
- /**回调 即解析@RequestMapping 返回RequestMappingInfo
- * @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#getMappingForMethod(java.lang.reflect.Method, java.lang.Class)*/
- T result = metadataLookup.inspect(specificMethod);
- if (result != null) {
- // 看看有没有桥接方法:泛型实现类jvm会自动生成桥接类
- Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
- if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
- //把方法对象作为key,RequestMappingInfo对象作为value保存到map中
- methodMap.put(specificMethod, result);
- }
- }
- }, ReflectionUtils.USER_DECLARED_METHODS);
- }
-
- return methodMap;
- }
五、@RequestMapping映射源码
- /**
- * 获取@RequestMapping映射
- * 源码位置:org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(HttpServletRequest)
- */
- public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
- // 获取当前请求对应的HandlerMethod
- Object handler = getHandlerInternal(request);
-
- // 获取默认的handler
- if (handler == null) {
- handler = getDefaultHandler();
- }
-
- // 还是没有handler的时候返回null,404了
- if (handler == null) {
- return null;
- }
- // Bean name or resolved handler?
- // String类型?获取Bean
- if (handler instanceof String) {
- String handlerName = (String) handler;
- handler = obtainApplicationContext().getBean(handlerName);
- }
-
- // Ensure presence of cached lookupPath for interceptors and others
- if (!ServletRequestPathUtils.hasCachedPath(request)) {
- initLookupPath(request);
- }
-
- // 获取拦截器相关的调用链
- HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
-
- if (logger.isTraceEnabled()) {
- logger.trace("Mapped to " + handler);
- }
- else if (logger.isDebugEnabled() && !DispatcherType.ASYNC.equals(request.getDispatcherType())) {
- logger.debug("Mapped to " + executionChain.getHandler());
- }
-
- if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
- 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 = getCorsHandlerExecutionChain(request, executionChain, config);
- }
-
- return executionChain;
- }
-
- /**
- * 获取当前请求对应的HandlerMethod
- * 源码位置:org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getHandlerInternal(HttpServletRequest)
- */
- protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
- request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
- try {
- // 直接调用父类的getHandlerInternal方法
- return super.getHandlerInternal(request);
- }
- finally {
- ProducesRequestCondition.clearMediaTypesAttribute(request);
- }
- }
- /**
- * 获取当前请求对应的HandlerMethod---父类的
- * 源码位置:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(HttpServletRequest)
- */
- protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
- // 通过UrlPathHelper对象,用于来解析从们的request中解析出请求映射路径
- String lookupPath = initLookupPath(request);
- this.mappingRegistry.acquireReadLock();
- try {
- // 通过lookupPath解析最终的handler——HandlerMethod对象
- HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
- return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
- }
- finally {
- this.mappingRegistry.releaseReadLock();
- }
- }
-
- /**
- * 通过lookupPath解析最终的handler
- * 源码位置:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(String, HttpServletRequest)
- */
- protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
- List<Match> matches = new ArrayList<>();
- // 根据uri从mappingRegistry.pathLookup获取 RequestMappingInfo
- // pathLookup<path,RequestMappingInfo>会在初始化阶段解析好
- List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
- if (directPathMatches != null) {
- // 如果根据path能直接匹配的RequestMappingInfo 则用该mapping进行匹配其他条件(method、header等)
- addMatchingMappings(directPathMatches, matches, request);
- }
- if (matches.isEmpty()) {
- // 如果无path匹配,用所有的RequestMappingInfo 通过AntPathMatcher匹配
- addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
- }
- if (!matches.isEmpty()) {
- // 选择第一个为最匹配的
- Match bestMatch = matches.get(0);
- /**
- * 如果匹配到多个
- @RequestMapping(value="/mappin?")
- @RequestMapping(value="/mappin*")
- @RequestMapping(value="/{xxxx}")
- @RequestMapping(value="/**")
- */
- if (matches.size() > 1) {
- //创建MatchComparator的匹配器对象
- Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
-
- /** 根据精准度排序 大概是这样的: ? > * > {} >** 具体可以去看:
- * @see org.springframework.util.AntPathMatcher.AntPatternComparator#compare(java.lang.String, java.lang.String)*/
- matches.sort(comparator);
-
- // 排完序后拿到优先级最高的
- bestMatch = matches.get(0);
- if (logger.isTraceEnabled()) {
- logger.trace(matches.size() + " matching mappings: " + matches);
- }
- // 是否配置CORS并且匹配
- if (CorsUtils.isPreFlightRequest(request)) {
- for (Match match : matches) {
- if (match.hasCorsConfig()) {
- return PREFLIGHT_AMBIGUOUS_MATCH;
- }
- }
- }
- else {
- //获取第二最匹配的
- Match secondBestMatch = matches.get(1);
- //若第一个和第二个是一样的 抛出异常
- if (comparator.compare(bestMatch, secondBestMatch) == 0) {
- Method m1 = bestMatch.getHandlerMethod().getMethod();
- Method m2 = secondBestMatch.getHandlerMethod().getMethod();
- String uri = request.getRequestURI();
- throw new IllegalStateException(
- "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
- }
- }
- }
- //把最匹配的设置到request中
- request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
- handleMatch(bestMatch.mapping, lookupPath, request);
- //返回最匹配的
- return bestMatch.getHandlerMethod();
- }
- else { // return null
- return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
- }
- }
到此这篇关于java spring mvc处理器映射器介绍的文章就介绍到这了,更多相关spring mvc处理器映射器内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!