百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

原创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字符串复制...

二年级上册语文必考句子仿写,家长打印,孩子照着练

二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...

一年级语文上 句子专项练习(可打印)

...

亲自上阵!C++ 大佬深度“剧透”:C++26 将如何在代码生成上对抗 Rust?

...

取消回复欢迎 发表评论: