java spring mvc处理器映射器介绍

网友投稿 285 2022-08-17


java spring mvc处理器映射器介绍

目录一、RequestMappingHandlerMapping解析映射简单介绍二、@RequestMapping解析源码流程三、@RequestMapping映射源码流程四、@RequestMapping解析源码五、@RequestMapping映射源码

前言:

本文源码基于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 methods = MethodIntrospector.selectMethods(userType,

(MethodIntrospector.MetadataLookup) 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)

*/

public static Map selectMethods(Class> targetType, final MetadataLookup metadataLookup) {

final Map methodMap = new LinkedHashMap<>();

Set> 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 matches = new ArrayList<>();

// 根据uri从mappingRegistry.pathLookup获取 RequestMappingInfo

// pathLookup会在初始化阶段解析好

List 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 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);

}

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Netty分布式高性能工具类FastThreadLocal和Recycler分析
下一篇:Java spring mvc请求详情介绍
相关文章

 发表评论

暂时没有评论,来抢沙发吧~