原创005 | 搭上SpringBoot请求处理源码分析专车
liebian365 2024-10-19 07:56 22 浏览 0 评论
前言
如果这是你第二次看到师长,说明你在觊觎我的美色!
点赞+关注再看,养成习惯
没别的意思,就是需要你的窥屏^_^
专车介绍
该趟专车是开往Spring Boot请求处理源码分析专车,主要用来分析Spring Boot是如何将我们的请求路由到指定的控制器方法以及调用执行。
专车问题
- 为什么我们在控制器中添加一个方法,使用@RequestMapping注解标注,指定一个路径,就可以用来处理一个web请求?
- 如果多个方法的请求路径一致,Spring Boot是如何处理的?
专车示例
@RestController @RequestMapping("/persons") publicclassPersonController{ private static List<Person> personList = new ArrayList<>; static { personList.add(new Person(10001, "test1")); personList.add(new Person(10002, "test2")); personList.add(new Person(10003, "test3")); personList.add(new Person(10004, "test4")); personList.add(new Person(10005, "test5")); } @GetMapping("/") public List<Person> list { return personList; } @GetMapping("/{id}") public Person get(@PathVariable("id") Integer id) { Person defaultPerson = new Person(88888, "default"); return personList.stream.filter(person -> Objects.equals(person.getId, id)).findFirst.orElse(defaultPerson); } @PostMapping("/") publicvoidadd(@RequestBody Person person) { personList.add(person); } @PutMapping("/") publicvoidupdate(@RequestBody Person person) { personList.removeIf(p -> Objects.equals(p.getId, person.getId)); personList.add(person); } }
示例代码提供了GET、POST、PUT请求,接下里我们会结合示例进行源码分析
专车分析
此次分析主要从2个大的方面进行分析:请求初始化、请求处理
请求初始化
请求流程
一次完成的请求流程就是请求--->处理--->响应,业务逻辑处理最终交由我们创建的Servlet来进行处理。以前在使用Spring MVC框架的时候,我们都会在web.xml中配置一个DispathcherServlet。接下来就让我们来看看DispathcherServlet的类图
从如上图可以清晰的看到DispatcherServlet的继承关系。其中一个名为HttpServlet的类,如果写过Servlet的应该都比较的熟悉,以往基于Servlet开发,都会创建一个Servlet实现类,继承HttpServlet并重写service方法,最后在web.xml中配置我们我们创建的Servlet实现类,这样我们就可以使用创建的Servlet实现类来处理我们的web请求了。
HttpServlet初始化
在我们第一次请求的时候会进行Servlet的初始化,主要用来初始化资源。HttpServlet的init方法由父类GenericServlet声明,由子类HttpServletBean实现。
初始化方法:HttpServletBean#init
@Override public final void init throws ServletException { // ...省略部分代码 // Let subclasses do whatever initialization they like. // 暴露出去一个方法,可以让子类初始化一些自己想要初始化的内容 initServletBean; }
创建WebApplicationContext:FrameworkServlet#initServletBean
@Override protected final void initServletBean throws ServletException { // ...省略部分代码 try { // 初始化WebApplicationContext对象 this.webApplicationContext = initWebApplicationContext; // 空实现 initFrameworkServlet; } // ...省略部分代码 }
初始化WebApplicationContext对象:FrameworkServlet#initWebApplicationContext
protected WebApplicationContext initWebApplicationContext { // 获取WebApplicationContext对象 WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext); WebApplicationContext wac = ; // ... 省略部分代码 if (!this.refreshEventReceived) { // Either the context is not a ConfigurableApplicationContext with refresh // support or the context injected at construction time had already been // refreshed -> trigger initial onRefresh manually here. synchronized (this.onRefreshMonitor) { // 刷新资源 onRefresh(wac); } } if (this.publishContext) { // Publish the context as a servlet context attribute. String attrName = getServletContextAttributeName; getServletContext.setAttribute(attrName, wac); } return wac; }
刷新资源:DispatcherServlet#onRefresh
@Override protectedvoidonRefresh(ApplicationContext context) { initStrategies(context); }
初始化策略:DispatcherServlet#initStrategies
protectedvoidinitStrategies(ApplicationContext context) { // 初始化多文件解析器 initMultipartResolver(context); // 初始化本地化解析器 initLocaleResolver(context); // 初始化主题解析器 initThemeResolver(context); // 初始化HandlerMapping initHandlerMappings(context); // 初始化HandlerAdapter initHandlerAdapters(context); // 初始化异常解析器 initHandlerExceptionResolvers(context); // 初始化请求到视图名称翻译器 initRequestToViewNameTranslator(context); // 初始化视图解析器 initViewResolvers(context); initFlashMapManager(context); }
来看一下初始化HandlerMapping实现:DispatcherServlet#initHandlerMappings
privatevoidinitHandlerMappings(ApplicationContext context) { this.handlerMappings = ; if (this.detectAllHandlerMappings) { // Find all HandlerMappings in the ApplicationContext, including ancestor contexts. // 从IOC容器中获取类型为HandlerMapping的bean // 对应的bean有RequestMappingHandlerMapping、SimpleUrlHandlerMapping、WelcomePageHandlerMapping Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty) { this.handlerMappings = new ArrayList<>(matchingBeans.values); // We keep HandlerMappings in sorted order. // 对HandlerMapping进行排序 AnnotationAwareOrderComparator.sort(this.handlerMappings); } } }
通过对初始化HandlerMapping实现的分析,我们可以得出,所有的初始化操作就是从IOC容器中获取相应类型的Bean,然后进行属性赋值。
既然能从IOC容器中获取到HandlerMapping bean,那么一定存在定义bean 的地方。打开WebMvcAutoConfiguration类,可以看到如下代码
/** * Configuration equivalent to {@code @EnableWebMvc}. * 此配置等同于使用@EnableWebMvc注解 */ @Configuration public staticclassEnableWebMvcConfigurationextendsDelegatingWebMvcConfiguration{ private final WebMvcProperties mvcProperties; private final ListableBeanFactory beanFactory; private final WebMvcRegistrations mvcRegistrations; publicEnableWebMvcConfiguration( ObjectProvider<WebMvcProperties> mvcPropertiesProvider, ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ListableBeanFactory beanFactory) { this.mvcProperties = mvcPropertiesProvider.getIfAvailable; this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique; this.beanFactory = beanFactory; } // 声明RequestMappingHandlerAdapter bean @Bean @Override public RequestMappingHandlerAdapter requestMappingHandlerAdapter { RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter; adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == || this.mvcProperties.isIgnoreDefaultModelOnRedirect); return adapter; } // 声明RequestMappingHandlerMapping bean @Bean @Primary @Override public RequestMappingHandlerMapping requestMappingHandlerMapping { // Must be @Primary for MvcUriComponentsBuilder to work return super.requestMappingHandlerMapping; } }
在如上代码中可以看到HandlerAdapter和HandlerMapping bean的声明
创建RequestMappingHandlerMapping
@Bean public RequestMappingHandlerMapping requestMappingHandlerMapping { // 创建RequestMappingHandlerMapping对象 RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping; // 设置属性 mapping.setOrder(0); // 设置拦截器 mapping.setInterceptors(getInterceptors); mapping.setContentNegotiationManager(mvcContentNegotiationManager); mapping.setCorsConfigurations(getCorsConfigurations); // ...省略部分代码 return mapping; }
可以看到除了创建RequestMappingHandlerMapping对象,其它的都是设置属性信息,接下来重点分析创建对象部分的代码
WebMvcConfigurationSupport#createRequestMappingHandlerMapping
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping { return new RequestMappingHandlerMapping; }
可以创建RequestMappingHandlerMapping对象的代码很简单,就是调用了无参数构造进行初始化。但是通过查看RequestMappingHandlerMapping的继承关系,我们可以看到该类实现了InitializingBean接口,这也就告诉我们当看到很简单的代码的时候,我们就要看看类的继承关系,来看看是否使用其他形式进行逻辑实现。
既然实现了InitializingBean接口,那就看看创建bean后的初始化方法afterPropertiesSet
@Override publicvoidafterPropertiesSet { this.config = new RequestMappingInfo.BuilderConfiguration; this.config.setUrlPathHelper(getUrlPathHelper); this.config.setPathMatcher(getPathMatcher); this.config.setSuffixPatternMatch(this.useSuffixPatternMatch); this.config.setTrailingSlashMatch(this.useTrailingSlashMatch); this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch); this.config.setContentNegotiationManager(getContentNegotiationManager); // 调用父类的初始化方法 super.afterPropertiesSet; }
@Override publicvoidafterPropertiesSet { // 初始化处理方法 initHandlerMethods; }
初始化处理方法:AbstractHandlerMethodMapping#initHandlerMethods
protectedvoidinitHandlerMethods { // 获取并遍历候选bean名称,候选bean就是从IOC容器中获取类型为Object的bean名称,也就是所有的Bean名称 for (String beanName : getCandidateBeanNames) { // 如果bean的名称不以“scopedTarget.”开头,才进行处理 if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { // 处理候选bean名称 processCandidateBean(beanName); } } handlerMethodsInitialized(getHandlerMethods); }
处理候选bean名称:AbstractHandlerMethodMapping#processCandidateBean
protectedvoidprocessCandidateBean(String beanName) { Class<?> beanType = ; try { // 根据bean的名称获取对应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); } } // 如果bean的类型不为空并且对应类上含有@Controller注解或者@RequestMapping注解 if (beanType != && isHandler(beanType)) { // 推断处理方法 detectHandlerMethods(beanName); } }
推断处理方法:AbstractHandlerMethodMapping#detectHandlerMethods
protectedvoiddetectHandlerMethods(Object handler) { // 根据bean名称获取类型 Class<?> handlerType = (handler instanceof String ? obtainApplicationContext.getType((String) handler) : handler.getClass); if (handlerType != ) { Class<?> userType = ClassUtils.getUserClass(handlerType); // 获取处理方法 Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> { try { // selectMethods方法获取当前类中所有的方法,针对PersonController类就有list、get、add、update四个方法,遍历这四个方法,分别创建对应的RequestMappingInfo对象 // 根据method获取RequestMappingInfo对象 return getMappingForMethod(method, userType); } }); if (logger.isTraceEnabled) { logger.trace(formatMappings(userType, methods)); } methods.forEach((method, mapping) -> { Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); registerHandlerMethod(handler, invocableMethod, mapping); }); } }
根据method获取RequestMappingInfo对象:RequestMappingHandlerMapping#getMappingForMethod
@Override @able protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { // 根据method对象创建RequestMappingInfo对象 RequestMappingInfo info = createRequestMappingInfo(method); if (info != ) { // 如果当前方法所在的类也含有@RequestMapping对象,那么也创建一个RequestMappingInfo对象 RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType); if (typeInfo != ) { // 将两个RequestMappingInfo对象进行合并,比如我们PersonController上指定@RequestMapping("/persons"),针对list方法,list方法上指定@RequestMapping("/"),那么合并后的映射路径就是/persons/ info = typeInfo.combine(info); } String prefix = getPathPrefix(handlerType); if (prefix != ) { info = RequestMappingInfo.paths(prefix).build.combine(info); } } // 返回RequestMappingInfo对象 return info; }
回到推断处理方法中:AbstractHandlerMethodMapping#detectHandlerMethods
protectedvoiddetectHandlerMethods(Object handler) { // 根据bean名称获取类型 Class<?> handlerType = (handler instanceof String ? obtainApplicationContext.getType((String) handler) : handler.getClass); if (handlerType != ) { Class<?> userType = ClassUtils.getUserClass(handlerType); // 获取处理方法,每个方法都有对应的RequestMappingInfo对象 Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> { try { // selectMethods方法中当前类中所有的方法,针对PersonController类就有list、get、add、update四个方法,遍历这四个方法,分别创建对应的RequestMappingInfo对象 // 根据method获取RequestMappingInfo对象 return getMappingForMethod(method, userType); } }); if (logger.isTraceEnabled) { logger.trace(formatMappings(userType, methods)); } // 遍历处理方法 methods.forEach((method, mapping) -> { // 获取可以执行的method对象 Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); // 注册处理方法 registerHandlerMethod(handler, invocableMethod, mapping); }); } }
注册处理方法:AbstractHandlerMethodMapping.MappingRegistry#register
publicvoidregister(T mapping, Object handler, Method method) { // 加写锁,加锁是因为我们可以在代码中手动注册处理方法,为了防止并发问题,此处需要加锁处理 this.readWriteLock.writeLock.lock; try { // 创建HandlerMethod对象 HandlerMethod handlerMethod = createHandlerMethod(handler, method); assertUniqueMethodMapping(handlerMethod, mapping); // 将RequestMappingInfo对象和HandlerMethod对象添加到map集合中 this.mappingLookup.put(mapping, handlerMethod); List<String> directUrls = getDirectUrls(mapping); for (String url : directUrls) { // 将url和RequestMappingInfo对象添加到map集合中 this.urlLookup.add(url, mapping); } String name = ; if (getNamingStrategy != ) { name = getNamingStrategy.getName(handlerMethod, mapping); addMappingName(name, handlerMethod); } CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping); if (corsConfig != ) { this.corsLookup.put(handlerMethod, corsConfig); } // 将RequestMappingInfo和MappingRegistration对象添加到map集合中 this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name)); } finally { // 释放锁 this.readWriteLock.writeLock.unlock; } }
所有方法遍历完成后的结果如下:
到此RequestMappingHandlerMapping对象创建初始化就结束了
RequestMappingHandlerMapping对象创建总结
- 调用afterPropertiesSet初始化方法
- 获取所有的bean名称
- 遍历所有的bean名称,如果bean名称不是以”scopedTarget.“开头就继续处理
- 根据bean名称获取bean类型,获取对应的类型上是否含有@Controller注解或@RequestMapping注解,如果有就继续处理
- 获取当前类中所有的方法,遍历所有的方法
- 根据Method对象生成RequestMappingInfo对象,如果类上也很有@RequestMapping注解,那么也生成RequestMappingInfo对象,将这两个RequestMappingInfo对象进行合并
- 遍历Method、RequestMappingInfo对应的map集合并注册到对应的mappingLookup、urlLookup、registry集合中
创建RequestMappingHandlerAdapter
创建RequestMappingHandlerAdapter:WebMvcAutoConfiguration.EnableWebMvcConfiguration#requestMappingHandlerAdapter
@Bean @Override public RequestMappingHandlerAdapter requestMappingHandlerAdapter { // 调用父类创建RequestMappingHandlerAdapter对象 RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter; // ...省略部分代码 return adapter; }
调用父类创建RequestMappingHandlerAdapter:WebMvcConfigurationSupport#requestMappingHandlerAdapter
@Bean public RequestMappingHandlerAdapter requestMappingHandlerAdapter { // 创建RequestMappingHandlerAdapter对象 RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter; // 省略部分代码 return adapter; }
请求处理
请求处理流程
- 遍历所有的HandlerMapping对象,找到匹配当前请求对应的HandlerMethod
- 将HandlerMethod包装成HandlerExecutionChain对象
- 根据HandlerMethod找到HandlerAdapter
- HandlerAdapter执行HandlerMethod
匹配HandlerMethod并包装成HandlerExecutionChain对象
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerExecutionChain mappedHandler = ; // 匹配HandlerMethod并包装成HandlerExecutionChain对象 mappedHandler = getHandler(processedRequest); }
获取HandlerExecutionChain对象:DispatcherServlet#getHandler
@able protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != ) { // 遍历所有的HandlerMapping for (HandlerMapping mapping : this.handlerMappings) { // 根据HandlerMapping获取HandlerExecutionChain对象,此处的HandlerMapping就是上面分析过的RequestMappingHandlerMapping对象 HandlerExecutionChain handler = mapping.getHandler(request); // 如果获取到HandlerExecutionChain对象,那么直接将HandlerExecutionChain对象返回 if (handler != ) { return handler; } } } return ; }
根据HandlerMapping获取HandlerExecutionChain对象:AbstractHandlerMapping#getHandler
@Override @able public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { // 获取HandlerMethod对象 Object handler = getHandlerInternal(request); // ...省略部分代码 HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); // ...省略部分代码 return executionChain; }
获取HandlerMethod对象
@Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { // 获取请求的路径,假设此处请求的路径为/persons/ String lookupPath = getUrlPathHelper.getLookupPathForRequest(request); // 加锁 this.mappingRegistry.acquireReadLock; try { // 寻找HandlerMethod对象 HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); // 获取HandlerMethod所在类对应的bean,然后创建HandlerMethod对象 return (handlerMethod != ? handlerMethod.createWithResolvedBean : ); } finally { // 释放锁 this.mappingRegistry.releaseReadLock; } }
寻找HandlerMethod对象:AbstractHandlerMethodMapping#lookupHandlerMethod
在该方法之前再看一下上文中对RequestMappingHandlerMapping分析的结果
@able protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List<Match> matches = new ArrayList<>; // 从urlLookup属性中找到当前请求路径对应的RequestMappingInfo信息 // 假设请求的路径为/persons/,那么此处得到的结果有3个 List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); if (directPathMatches != ) { // 寻找最匹配的RequestMappingInfo // 匹配的方式包括:请求方法、请求header、请求参数等 addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty) { // No choice but to go through all mappings... addMatchingMappings(this.mappingRegistry.getMappings.keySet, matches, request); } if (!matches.isEmpty) { Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); matches.sort(comparator); Match bestMatch = matches.get(0); if (matches.size > 1) { if (logger.isTraceEnabled) { logger.trace(matches.size + " matching mappings: " + matches); } if (CorsUtils.isPreFlightRequest(request)) { return PREFLIGHT_AMBIGUOUS_MATCH; } Match secondBestMatch = matches.get(1); // 如果存在多个匹配结果,就报错 if (comparator.compare(bestMatch, secondBestMatch) == 0) { Method m1 = bestMatch.handlerMethod.getMethod; Method m2 = secondBestMatch.handlerMethod.getMethod; String uri = request.getRequestURI; throw new IllegalStateException( "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}"); } } request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod); handleMatch(bestMatch.mapping, lookupPath, request); // 返回匹配的HandlerMethod return bestMatch.handlerMethod; } else { return handleNoMatch(this.mappingRegistry.getMappings.keySet, lookupPath, request); } }
获取HandlerAdapter
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler); }
获取HandlerAdapter:DispatcherServlet#getHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != ) { for (HandlerAdapter adapter : this.handlerAdapters) { // 如果当前HandlerAdapter支持当前要处理的HnadlerMethod,那么就返回此HandlerAdapter if (adapter.supports(handler)) { return adapter; } } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
匹配方法:此处拿RequestMappingHandlerAdapter举例,调用AbstractHandlerMethodAdapter#supports
publicfinalbooleansupports(Object handler) { // 如果当前的hander是HandlerMethod,则返回true;后一个表达式直接返回的就是true return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler)); }
从如上分析可以得出的结论就是最终返回的HandlerAdapter为RequestMappingHandlerAdapter
HandlerAdapter执行HandlerMethod
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { mv = ha.handle(processedRequest, response, mappedHandler.getHandler); }
处理目标方法:RequestMappingHandlerAdapter#handleInternal
@Override protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; checkRequest(request); // Execute invokeHandlerMethod in synchronized block if required. if (this.synchronizeOnSession) { // ...省略部分代码 } else { // No synchronization on session demanded at all... // 调用HandlerMethod方法 mav = invokeHandlerMethod(request, response, handlerMethod); } // ...省略部分代码 return mav; }
调用HandlerMethod方法:RequestMappingHandlerAdapter#invokeHandlerMethod
@able protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); try { WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); // 创建ServletInvocableHandlerMethod对象,就是把handlerMethod对象的属性赋值给ServletInvocableHandlerMethod对象的属性 ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); // ...省略部分代码 // 调用方法并处理返回值 invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted) { return ; } return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted; } }
调用方法并处理返回值:ServletInvocableHandlerMethod#invokeAndHandle
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 执行请求,获取返回值 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); // ...省略部分代码 mavContainer.setRequestHandled(false); Assert.state(this.returnValueHandlers != , "No return value handlers"); try { // 处理返回值 this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } }
执行请求:InvocableHandlerMethod#invokeForRequest
@able public Object invokeForRequest(NativeWebRequest request, @able ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 获取方法参数 Object args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled) { logger.trace("Arguments: " + Arrays.toString(args)); } // 目标方法调用 return doInvoke(args); }
目标方法调用:InvocableHandlerMethod#doInvoke
@able protected Object doInvoke(Object... args) throws Exception { ReflectionUtils.makeAccessible(getBridgedMethod); try { // 通过反射执行目标方法 return getBridgedMethod.invoke(getBean, args); } // ...省略部分代码 }
到此请求处理的源码分析就结束了,最终再来看看doDispatch完整的方法:DispatcherServlet#doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = ; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = ; Exception dispatchException = ; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Determine handler for the current request. // 1、获取handler mappedHandler = getHandler(processedRequest); if (mappedHandler == ) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. // 2、获取HandlerAdapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler); // Process last-modified header, if supported by the handler. String method = request.getMethod; boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // 执行拦截器的前置方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. // 调用目标方法 mv = ha.handle(processedRequest, response, mappedHandler.getHandler); if (asyncManager.isConcurrentHandlingStarted) { return; } applyDefaultViewName(processedRequest, mv); // 执行拦截器的处理方法 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } // 处理结果 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { // 执行拦截器的后置方法,常用语释放资源 triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { // 执行拦截器的后置方法,常用语释放资源 triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } finally { if (asyncManager.isConcurrentHandlingStarted) { // Instead of postHandle and afterCompletion if (mappedHandler != ) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
专车总结
一次请求原理如下:
- 请求初始化
- 请求处理
请求初始化
- 初始化RequestMappingHandlerMapping
- 初始化RequestMappingHandlerAdapter
请求处理
- 获取HandlerMethod,组装HandlerExecutionChain对象
- 获取HandlerAdapter
- 使用HandlerAdapter执行HandlerMethod
专车回顾
- 为什么我们在控制器中添加一个方法,使用@RequestMapping注解标注,指定一个路径,就可以用来处理一个web请求?因为在初始化过程中,会将请求路径和处理方法进行绑定,我们在请求ulr的时候,匹配到我们对应的处理方法,然后调用处理方法,就可以执行此次的ewb请求了。
- 如果多个方法的请求路径一致,Spring Boot是如何处理的?如果多个方法的请求路径一致,会拿请求方法、请求参数、请求header等,最终会匹配出最符合的一个处理方法,如果匹配出多个结果,就会报错。
专车遗漏问题
- SpringBoot如何处理请求参数
- SpringBoot如何处理返回结果
- SpringBoot拦截器如何工作
专车扩展
如果是基于微服务开发,那么该如何定义我们的服务?
定义微服务接口:
@RequestMapping("/persons") publicinterfacePersonApi{ /** * list * * @return */ @GetMapping("/") List<Person> list; /** * get * * @param id * @return */ @GetMapping("/{id}") Person get(@PathVariable("id") Integer id); /** * add * * @param person * @return */ @PostMapping("/") voidadd(@RequestBody Person person); /** * update * * @param person * @return */ @PutMapping("/") voidupdate(@RequestBody Person person); }
定义接口实现:
@RestController publicclassPersonControllerimplementsPersonApi{ private static List<Person> personList = new ArrayList<>; static { personList.add(new Person(10001, "test1")); personList.add(new Person(10002, "test2")); personList.add(new Person(10003, "test3")); personList.add(new Person(10004, "test4")); personList.add(new Person(10005, "test5")); } @Override public List<Person> list { return personList; } @Override public Person get(Integer id) { Person defaultPerson = new Person(88888, "default"); return personList.stream.filter(person -> Objects.equals(person.getId, id)).findFirst.orElse(defaultPerson); } @Override publicvoidadd(Person person) { personList.add(person); } @Override publicvoidupdate(Person person) { personList.removeIf(p -> Objects.equals(p.getId, person.getId)); personList.add(person); } }
———— e n d ————
最后
师长,【java进阶架构师】号主,短短一年在各大平台斩获15W+程序员关注,专注分享Java进阶、架构技术、高并发、微服务、BAT面试、redis专题、JVM调优、Springboot源码、mysql优化等20大进阶架构专题。
相关推荐
- 4万多吨豪华游轮遇险 竟是因为这个原因……
-
(观察者网讯)4.7万吨豪华游轮搁浅,竟是因为油量太低?据观察者网此前报道,挪威游轮“维京天空”号上周六(23日)在挪威近海发生引擎故障搁浅。船上载有1300多人,其中28人受伤住院。经过数天的调...
- “菜鸟黑客”必用兵器之“渗透测试篇二”
-
"菜鸟黑客"必用兵器之"渗透测试篇二"上篇文章主要针对伙伴们对"渗透测试"应该如何学习?"渗透测试"的基本流程?本篇文章继续上次的分享,接着介绍一下黑客们常用的渗透测试工具有哪些?以及用实验环境让大家...
- 科幻春晚丨《震动羽翼说“Hello”》两万年星间飞行,探测器对地球的最终告白
-
作者|藤井太洋译者|祝力新【编者按】2021年科幻春晚的最后一篇小说,来自大家喜爱的日本科幻作家藤井太洋。小说将视角放在一颗太空探测器上,延续了他一贯的浪漫风格。...
- 麦子陪你做作业(二):KEGG通路数据库的正确打开姿势
-
作者:麦子KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。你需要了解你的分子目前已有哪些...
- 知存科技王绍迪:突破存储墙瓶颈,详解存算一体架构优势
-
智东西(公众号:zhidxcom)编辑|韦世玮智东西6月5日消息,近日,在落幕不久的GTIC2021嵌入式AI创新峰会上,知存科技CEO王绍迪博士以《存算一体AI芯片:AIoT设备的算力新选择》...
- 每日新闻播报(September 14)_每日新闻播报英文
-
AnOscarstatuestandscoveredwithplasticduringpreparationsleadinguptothe87thAcademyAward...
- 香港新巴城巴开放实时到站数据 供科技界研发使用
-
中新网3月22日电据香港《明报》报道,香港特区政府致力推动智慧城市,鼓励公私营机构开放数据,以便科技界研发使用。香港运输署21日与新巴及城巴(两巴)公司签署谅解备忘录,两巴将于2019年第3季度,开...
- 5款不容错过的APP: Red Bull Alert,Flipagram,WifiMapper
-
本周有不少非常出色的app推出,鸵鸟电台做了一个小合集。亮相本周榜单的有WifiMapper's安卓版的app,其中包含了RedBull的一款新型闹钟,还有一款可爱的怪物主题益智游戏。一起来看看我...
- Qt动画效果展示_qt显示图片
-
今天在这篇博文中,主要实践Qt动画,做一个实例来讲解Qt动画使用,其界面如下图所示(由于没有录制为gif动画图片,所以请各位下载查看效果):该程序使用应用程序单窗口,主窗口继承于QMainWindow...
- 如何从0到1设计实现一门自己的脚本语言
-
作者:dong...
- 三年级语文上册 仿写句子 需要的直接下载打印吧
-
描写秋天的好句好段1.秋天来了,山野变成了美丽的图画。苹果露出红红的脸庞,梨树挂起金黄的灯笼,高粱举起了燃烧的火把。大雁在天空一会儿写“人”字,一会儿写“一”字。2.花园里,菊花争奇斗艳,红的似火,粉...
- C++|那些一看就很简洁、优雅、经典的小代码段
-
目录0等概率随机洗牌:1大小写转换2字符串复制...
- 二年级上册语文必考句子仿写,家长打印,孩子照着练
-
二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)