Springmvc是如何根据url路径到对应的controller⽅法的
>>>>#更新:
SpringMVC的请求处理过程中的路径匹配过程:
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod
(spring-webmvc-4.2.3.RELEASE)
路径匹配的过程中有如下代码:
List<Match> matches = new ArrayList<Match>();
List<T> directPathMatches = MappingsByUrl(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through
addMatchingMappings(Mappings().keySet(), matches, request);
}
SpringMVC⾸先对HTTP请求中的path与已注册的RequestMappingInfo(经解析的@RequestMapping)中的path进⾏⼀个完全匹配来查对应的HandlerMethod,即处理该请求的⽅法,**这个匹配就是⼀个Map#get⽅法**。若不到则会遍历所有的RequestMappingInfo进⾏查。这个查是不会提前停⽌的,直到遍历完全部的RequestMappingInfo。
这⾥主要是springmvc在项⽬启动时根据requestMapping中api的访问路径封装了不同的map对象,对于纯path请求就是从map中直接get,⽽对于使⽤了pathVariable注解的请求则需要去map对象中到所有满⾜条件的对象然后取最优解。
public RequestMappingInfo getMatchingCondition(HttpServletRequest request){
RequestMethodsRequestCondition methods =MatchingCondition(request);
ParamsRequestCondition params =MatchingCondition(request);
HeadersRequestCondition headers =MatchingCondition(request);
ConsumesRequestCondition consumes =MatchingCondition(request);
ProducesRequestCondition produces =MatchingCondition(request);
if(methods == null || params == null || headers == null || consumes == null || produces == null){
if(CorsUtils.isPreFlightRequest(request)){
methods =getAccessControlRequestMethodCondition(request);
if(methods == null || params == null){
return null;
}
}
else{
return null;
}
}
PatternsRequestCondition patterns =MatchingCondition(request);
if(patterns == null){
return null;
}
RequestConditionHolder custom =MatchingCondition(request);
if(custom == null){
return null;
}
return new RequestMappingInfo(this.name, patterns,
methods, params, headers, consumes, produces, Condition());
}
org.springframework.web.hod.RequestMappingInfo#getMatchingCondition
在遍历过程中,SpringMVC⾸先会根据@RequestMapping中的headers, params, produces, consumes, methods与实际的HttpServletRequest中的信息对⽐,剔除掉⼀些明显不合格的RequestMapping。 如果以上信息都能够匹配上,那么SpringMVC会对RequestMapping中的path进⾏正则匹配,剔除不合格的。
Comparator comparator = new MatchComparator(getMappingComparator(request));
Collections.sort(matches, comparator);
接下来会对所有留下来的候选@RequestMapping进⾏评分并排序。最后选择分数最⾼的那个作为结果。 评分的优先级为:
path pattern > params > headers > consumes > produces > methods
所以使⽤⾮RESTful风格的URL时,SpringMVC可以⽴刻到对应的HandlerMethod来处理请求。但是当在URL中存在变量时,即使⽤了@PathVariable时,SpringMVC就会进⾏上述的复杂流程。
值得注意的是SpringMVC在匹配@RequestMapping中的path时是通过AntPathMatcher进⾏的,这段path匹配逻辑是从Ant中借鉴过来的。
####END
使⽤restful风格时,我们往往会在⼀个controller⽅法使⽤同⼀个路径,然后定义不同的httpmethod,那么问题来了,springmvc是怎么做到的呢?
⾸先,看下我们的Controller层代码
@SpringBootApplicationspringmvc的注解有哪些
@EnableEurekaServer
@RestController
public class EurekaServerApplication {
public static void main(String[] args){
SpringApplication.run(EurekaServerApplication.class, args);
}
@GetMapping("/hi")
public String hi(){
StringBuilder sb =new StringBuilder();
sb.append("<div style=\"color:red;\">aaaaa</div>")
.der().encodeForHTML("<script>alert(1)</script>"));
String jsCode ="<div style=\"color:red;\">aaaaa</div><script>alert(1)</script>";
String jsEncoder = der().encodeForHTML(jsCode);
System.out.println(">>>>>>>>>>>####");
System.out.String());
String();
}
@GetMapping("/hi/{id}")
public void getId(@PathVariable String id, String name){
System.out.println("hello, "+ id +"name:"+ name);
}
@PostMapping("/hi/{id}")
public void postId(@PathVariable String id, String name){
System.out.println("hello, "+ id +"name:"+ name);
}
}
根据路径"/hi/{id}"定义了⼀个get⽅法和post⽅法。
项⽬启动时,springmvc会扫描所有类,将加了mapping的注解的⽅法和url绑定,存进⼀个全局的mappingLookup,这⾥怎么匹配的就不详细介绍了。
createHandlerMethod 会帮我们创建⼀个HandlerMethod对象
* Create an instance from a bean instance and a method.
*/
public HandlerMethod(Object bean, Method method){
this.bean = bean;
this.beanFactory = null;
this.beanType = UserClass(bean);
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
this.parameters =initMethodParameters();
evaluateResponseStatus();
}
这⾥会循环遍历七种mappinghandler获取最终的handler对象
这七个handler都继承了抽象类AbstractHandlerMapping,此抽象类中的⽅法getHandler⽤于获取handler 对象
* Look up a handler for the given request, falling back to the default
* handler if no specific one is found.
* @param request current HTTP request
* @return the corresponding handler instance, or the default handler
* @see #getHandlerInternal
*/
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request)throws Exception {
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 =obtainApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain =getHandlerExecutionChain(handler, request);
if(logger.isTraceEnabled()){
}
else if(logger.isDebugEnabled()&&!DispatcherType().equals(DispatcherType.ASYNC)){
logger.debug("Mapped to "+ Handler());
}
if(CorsUtils.isCorsRequest(request)){
CorsConfiguration globalConfig =CorsConfiguration(request);
CorsConfiguration handlerConfig =getCorsConfiguration(handler, request);
CorsConfiguration config =(globalConfig != null ? globalConfigbine(handlerConfig): handlerConfig);  executionChain =getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。

发表评论