- 下图是springmvc的执行流程
图片来源:https://www.jianshu.com/p/8a20c547e245
DispatcherServlet根据url定位到Controller和方法,依赖的是HandlerMapping接口的各个实现类,其中,RequestMappingHandlerMapping是专门用来处理注解方式的Controller的
下面,我们分RequestMappingHandlerMapping的加载以及RequestMappingHandlerMapping如何根据url定位Controller两部分来讲
RequestMappingHandlerMapping加载过程
- RMHP在系统启动时会被注册成bean,见《springmvc源码笔记-HandlerMapping注入》
-
因为RMHP实现了InitializingBean接口,在bean加载完成后会自动调用afterPropertiesSet方法,在此方法中调用了AbstractHandlerMethodMapping#initHandlerMethods()来实现初始化
protected void initHandlerMethods() { // 遍历所有的bean for (String beanName : getCandidateBeanNames()) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { processCandidateBean(beanName); } } handlerMethodsInitialized(getHandlerMethods()); } protected void processCandidateBean(String beanName) { Class<?> beanType = null; try { beanType = obtainApplicationContext().getType(beanName); } ...... // isHandler判断类是否有Controller或者RequestMapping注解 if (beanType != null && isHandler(beanType)) { detectHandlerMethods(beanName); } } protected void detectHandlerMethods(Object handler) { ...... if (handlerType != null) { Class<?> userType = ClassUtils.getUserClass(handlerType); // 遍历类的所有方法 Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> { try { // 获取方法上的映射(会读取方法上的RequestMapping注解获取url) return getMappingForMethod(method, userType); } catch (Throwable ex) { throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, ex); } }); ...... methods.forEach((method, mapping) -> { Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); // 将映射关系放入AbstractHandlerMethodMapping.mappingRegistry中 registerHandlerMethod(handler, invocableMethod, mapping); }); } }
RequestMappingHandlerMapping解析过程
- DispatcherServlet继承HttpServlet,所以执行链是FrameworkServlet#doGet→DispatcherServlet#doService→DispatcherServlet#doDispatch→DispatcherServlet#getHandler
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { // handlerMappings已在onRefresh方法中初始化 for (HandlerMapping mapping : this.handlerMappings) { // 第一个mapping就是RequestMappingHandlerMapping // 获取处理程序,也就是url对应的controller和method HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; } // AbstractHandlerMapping#getHandler->RequestMappingHandlerMapping#getHandlerInternal->AbstractHandlerMapping#lookupHandlerMethod protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { // lookupPath就是请求路径 List<Match> matches = new ArrayList<>(); // 获取url路径匹配项 List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath); if (directPathMatches != null) { // 添加映射匹配集合 addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request); } if (!matches.isEmpty()) { ...... // 至此,根据url获取到controller和method return bestMatch.getHandlerMethod(); } else { return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request); } } private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) { for (T mapping : mappings) { T match = getMatchingMapping(mapping, request); if (match != null) { // this.mappingRegistry.getRegistrations().get(mapping)就是获取HandlerMethodMapping // HandlerMethodMapping保存controller和method信息的类 matches.add(new Match(match, this.mappingRegistry.getRegistrations().get(mapping))); } } }
暂无评论