java spring mvc处理器映射器介绍

作者:hqx 时间:2021-11-22 01:01:35 

前言:

  • 本文源码基于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解析源码

/**
* 解析的开始位置。
* 由于实现了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);
}
}

来源:https://www.cnblogs.com/zfcq/p/16069331.html

标签:java,spring,mvc,处理器,映射器
0
投稿

猜你喜欢

  • ios百度地图的使用(普通定位、反地理编码)

    2023-07-03 15:26:17
  • Mybatis基础概念与高级应用小结

    2023-11-26 20:18:22
  • JAVA求两直线交点和三角形内外心的方法

    2023-07-30 02:46:35
  • Java获取json数组对象的实例讲解

    2023-08-24 14:55:28
  • Java IO文件后缀名过滤总结

    2021-09-01 23:36:47
  • Java中synchronized锁的深入理解

    2023-08-18 01:36:55
  • 一文搞懂Mybatis-plus的分页查询操作

    2023-11-25 10:23:17
  • Mybatis如何配置连接池

    2021-10-22 03:06:47
  • Spring Cloud项目前后端分离跨域的操作

    2022-05-20 08:11:16
  • Java synchronized锁升级jol过程详解

    2023-04-15 04:58:51
  • SpringIOC BeanDefinition的加载流程详解

    2023-11-25 18:06:22
  • maven手动上传jar包示例及图文步骤过程

    2023-11-13 22:10:57
  • Java中七种排序算法总结分析

    2023-03-27 19:41:44
  • Java实现按行读取大文件

    2022-11-05 13:56:57
  • SpringBoot 二维码生成base64并上传OSS的实现示例

    2023-05-12 04:41:33
  • JAVA内存模型(JMM)详解

    2023-11-23 16:54:32
  • Springboot WebJar打包及使用实现流程解析

    2023-06-21 22:08:00
  • Maven入门之使用Nexus搭建Maven私服及上传下载jar包

    2022-05-06 20:47:43
  • java高并发ScheduledThreadPoolExecutor与Timer区别

    2023-08-11 03:08:29
  • Spring boot热部署devtools过程解析

    2022-06-21 13:12:09
  • asp之家 软件编程 m.aspxhome.com