服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - java spring mvc处理器映射器介绍

java spring mvc处理器映射器介绍

2022-10-28 11:28hqx Java教程

这篇文章主要介绍了java spring mvc处理器映射器,文章围绕equestMapping解析映射介绍展开源码内容,具有一定的参考价值,需要的小伙伴可以参考一下

前言:

  • 本文源码基于spring-framework-5.3.10
  • mvcspring源码中的一个子模块!

一、RequestMappingHandlerMapping解析映射简单介绍

  • @RequestMapping通过RequestMappingHandlerMapping进行解析!
  • HandlerMapping是一个根据URL映射到Handler的方法。
  • RequestMappingHandlerMapping是HandlerMapping的一个子类!
  • RequestMappingHandlerMapping他的父类有InitializingBean,所有在spring启动实例化的时候会调用afterPropertiesSet()方法。解析逻辑就在这里。
  • RequestMappingHandlerMapping有俩个过程:解析、映射

二、@RequestMapping解析源码流程

  • 容器加载,调用RequestMappingHandlerMappingafterPropertiesSet()。
  • 调用父类的afterPropertiesSet()方法。
  • 调用initHandlerMethods()方法。
  • 循环每一个Bean,看方法上有@RequestMapping或者@Controller的Bean。
  • 解析HandlerMethods,进行封装RequestMappingInfo。
  • 将封装好的RequestMappingInfo存起来:key为路径,值为mapping(RequestMappingInfo)

三、@RequestMapping映射源码流程

  • 请求进来,调用getHandler方法。
  • 获取当前请求对应的HandlerMethod
  • 通过UrlPathHelper对象,用于来解析从们的request中解析出请求映射路径。
  • 更具路径去pathLookup中找。
  • 上面没找到,从所有的里面找有通配符的。
  • 找到多个进行排序,优先级:? > * > {} >** 。
  • 不为空拿到第一个返回。
  • 如果为空获取默认的。默认还是空的,直接返回null。
  • 封装拦截器,返回。

四、@RequestMapping解析源码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/**
 * 解析的开始位置。
 * 由于实现了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映射源码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/**
 * 获取@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处理器映射器内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/zfcq/p/16069331.html

延伸 · 阅读

精彩推荐