springboot启动、请求处理流程

本篇文章目的

这篇文章核心要研究的几个问题,是了解spring启动过程、请求处理的关键流程步骤

以常见的springboot为例。

  • springboot java -jar是如何实现的
  • springboot还有哪些启动方式,相比有什么区别和优缺点
  • 代码中的bean什么时候注册的,bean实例化、autowired、postconstructor、afterProperties的顺序和调用时机
  • springboot如何启动tomcat、Filter bean、DispatcherServlet是如何注册到tomcat中的
  • spring在处理http请求时,如何找到对应的方法的,参数如何解析的、@ResponseBody注解为什么可以把结果转换成json对象

spring boot是如何启动的

springboot项目常见的是两种启动方式,一种是开发阶段idea启动,调用main方法,另一种是部署,使用java -jar xxx.jar,我们主要研究-jar启动的方式。

spring-boot-maven-plugin的package的时候,能够创建一个fatjar,其中包含了服务启动运行所有需要的依赖,结构如下。

├── BOOT-INF
│   ├── classes
│   │   ├── application.yml
│   │   ├── com
│   │   │   └── xxx
│   │   │       ├── XXXX.class  // 工程中的代码class文件,例如controller类等等
│   └── lib
│       ├── HikariCP-xxx.jar // 依赖的jar包
│       ├── activation-xxx.jar
│       ├── adapter-guava-xxx.jar
├── META-INF
│   ├── MANIFEST.MF
└── org
    └── springframework
        └── boot
            └── loader
                ├── ExecutableArchiveLauncher.class // spring的启动相关类
                ├── JarLauncher.class
                └── util
                    └── SystemPropertyUtils.class
                    ...

java -jar xxx.jar时,java会先搜索jar包的META-INF/MANIFEST.MF,从中找到Main-Class

Main-Class: org.springframework.boot.loader.JarLauncher Start-Class: com.xxx.XXXApplication Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ 

Main-Class是JarLauncher,MANIFEST.MF中还定义了spring需要的Start-Class, Spring-Boot-Classes, SPring-Boot-Lib等信息,Start-CLass是用户的springboot main方法代码入口,Boot-Classes和Lib是需要加入classpath的路径。 JarLauncher类如下,会调用new JarLauncher().launch(args)方法。JarLauncher集成自ExecutableArchiveLauncher

public class JarLauncher extends ExecutableArchiveLauncher {     public JarLauncher() {     }     public static void main(String[] args) throws Exception {         new JarLauncher().launch(args);     } } 

launch会找到所有的classpath的jar包,然后创建一个特定的ClassLoader(继承于URLClassLoader),把所有的jar包依赖和classes作为ClassLoader的classpath传入。

protected void launch(String[] args) throws Exception { // 设置java.protocol.handler.pkgs属性, URLStreamHandler 能够处理jar包里的URL JarFile.registerUrlProtocolHandler(); // 创建LaunchedURLClassLoader,传入getClassPathArchives(),getClassPathArchives返回所有的 ClassLoader classLoader = createClassLoader(getClassPathArchives()); // 用LaunchedURLClassLoader launcher启动main方法 launch(args, getMainClass(), classLoader); } 

org.springframework.boot.loader.ExecutableArchiveLauncher#getClassPathArchives 这个方***返回一个Archieve,里面包含内嵌Archive

protected List<Archive> getClassPathArchives() throws Exception { List<Archive> archives = new ArrayList(this.archive.getNestedArchives(this::isNestedArchive)); this.postProcessClassPathArchives(archives); return archives; } 

ExecutableArchiveLauncher 构造函数中,会创建createArchive,表示java -jar启动的那个jar包

public ExecutableArchiveLauncher() { try { this.archive = this.createArchive(); } catch (Exception var2) { throw new IllegalStateException(var2); } } 
protected final Archive createArchive() throws Exception { ProtectionDomain protectionDomain = getClass().getProtectionDomain(); CodeSource codeSource = protectionDomain.getCodeSource(); URI location = (codeSource != null) ? codeSource.getLocation().toURI() : null; String path = (location != null) ? location.getSchemeSpecificPart() : null; if (path == null) { throw new IllegalStateException("Unable to determine code source archive"); } File root = new File(path); if (!root.exists()) { throw new IllegalStateException("Unable to determine code source archive from " + root); } return (root.isDirectory() ? new ExplodedArchive(root) : new JarFileArchive(root)); } 

getNestedArchives(EntryFilter) ExecutableArchiveLauncher会过滤出BOOT-INF/classes文件夹和BOOT-INF/lib包下的所有的jar包

protected boolean isNestedArchive(Archive.Entry entry) { if (entry.isDirectory()) { return entry.getName().equals(BOOT_INF_CLASSES); } return entry.getName().startsWith(BOOT_INF_LIB); } 

然后用这个BOOT-INF/classes和BOOT-INF/lib包下的所有的jar包作为LaunchedURLClassLoader的classpath,LaunchedURLClassLoader继承于 URLClassLoader,classes文件和jar包就会作为url classpath,类加载的时候就能够按照classname找到对应的class文件。

protected ClassLoader createClassLoader(List<Archive> archives) throws Exception { List<URL> urls = new ArrayList<>(archives.size()); for (Archive archive : archives) { urls.add(archive.getUrl()); } return createClassLoader(urls.toArray(new URL[0])); } protected ClassLoader createClassLoader(URL[] urls) throws Exception { return new LaunchedURLClassLoader(urls, getClass().getClassLoader()); } 

创建好ClassLoader后,再看下launch方法

protected void launch(String[] args, String mainClass, ClassLoader classLoader) throws Exception { Thread.currentThread().setContextClassLoader(classLoader); this.createMainMethodRunner(mainClass, args, classLoader).run(); } protected MainMethodRunner createMainMethodRunner(String mainClass, String[] args, ClassLoader classLoader) { return new MainMethodRunner(mainClass, args); } 

MainMethodRunner.run从META-INF/MANIFEST.MF中找到mainClassName用LaunchedClassLoader进行类加载,然后用反射调用main方法。

public class MainMethodRunner { private final String mainClassName; private final String[] args; public MainMethodRunner(String mainClass, String[] args) { this.mainClassName = mainClass; this.args = args != null ? (String[])args.clone() : null; } public void run() throws Exception { Class<?> mainClass = Thread.currentThread().getContextClassLoader().loadClass(this.mainClassName); Method mainMethod = mainClass.getDeclaredMethod("main", String[].class); mainMethod.invoke((Object)null, this.args); } } 

我们编写的main方法

通过上面的流程执行到我们编写的main方法了。

@SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } 

SpringApplication.run

我们顺着SpringApplication.run(DemoApplication.class, args)看一下启动过程

创建SpringApplication对象时,springboot会从classpath中查找javax.servlet.Servlet判断是否是WEB应用(webApplicationType)。

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); } public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.bootstrapRegistryInitializers = new ArrayList<>( getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); } 

后面是正式的run流程。

public ConfigurableApplicationContext run(String... args) { long startTime = System.nanoTime(); DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null; configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); context.setApplicationStartup(this.applicationStartup); prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup); } listeners.started(context, timeTakenToStartup); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } try { Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime); listeners.ready(context, timeTakenToReady); } catch (Throwable ex) { handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } return context; } 

run方法中的关键步骤是

  • createApplicationContext: 创建spring ApplicationContext
  • prepareContext: 注册Configuration bean
  • refreshContext: 扫描class,注册bean definition;启动tomcat web,server,注册servlet, filter; 创建非Lazy bean;注册request mapping

createApplicationContext

protected ConfigurableApplicationContext createApplicationContext() { return this.applicationContextFactory.create(this.webApplicationType); } 

applicationContextFactory通过webApplicationType判断使用的是AnnotationConfigServletWebServerApplicationContext

picture 1

AnnotationConfigServletWebServerApplicationContext中有两个字段 reader可以注册bean scanner(ClassPathBeanDefinitionScanner)从classpath中scan出所有的符合条件(@Component等注解、)的bean

public AnnotationConfigServletWebServerApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); } 

prepareContext

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,             ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,             ApplicationArguments applicationArguments, Banner printedBanner) { ... // Load the sources,包括SpringApplication.run传入的Application.class Set<Object> sources = getAllSources(); // load会把Configuration bean注册到beanFactory中 load(context, sources.toArray(new Object[0])); ... } 

refresh

创建好ApplicationContext, prepare完成后后,会调用refreshContext。

AbstractApplicationContext.refresh()

1) invokeBeanFactoryPostProcessors

其中有一个ConfigurationClassPostProcessor,会对Configuration类进行处理(@SpringBootApplication就继承了@Configuration)。 component scan扫描包下所有的component并注册成bean,以及Configuration里的@Bean方法。 扫描的过程中,会把BeanDefinition注册到BeanDefinitionRegistry(beanFactory)

SourceClass doProcessConfigurationClass() { // Process any @ComponentScan annotations Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { for (AnnotationAttributes componentScan : componentScans) { // The config class is annotated with @ComponentScan -> perform the scan immediately Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // Check the set of scanned definitions for any further config classes and parse recursively if needed for (BeanDefinitionHolder holder : scannedBeanDefinitions) { BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); if (bdCand == null) { bdCand = holder.getBeanDefinition(); } if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } } // Process any @Import annotations processImports(configClass, sourceClass, getImports(sourceClass), filter, true); // Process any @ImportResource annotations AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); if (importResource != null) { String[] resources = importResource.getStringArray("locations"); Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader"); for (String resource : resources) { String resolvedResource = this.environment.resolveRequiredPlaceholders(resource); configClass.addImportedResource(resolvedResource, readerClass); } } // Process individual @Bean methods Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } } 

refresh完成后,beandefinition完成了注册,但是bean还没有创建(实例化)

2) onRefresh

onRefresh会调用ServletWebServerApplicationContext.onRefresh, createWebServer创建了一个servlet server(默认tomcat)

protected void onRefresh() { super.onRefresh(); try { createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start web server", ex); } } private void createWebServer() {         WebServer webServer = this.webServer;         ServletContext servletContext = getServletContext();         if (webServer == null && servletContext == null) {             StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");             ServletWebServerFactory factory = getWebServerFactory();             createWebServer.tag("factory", factory.getClass().toString());             this.webServer = factory.getWebServer(getSelfInitializer());             createWebServer.end();             getBeanFactory().registerSingleton("webServerGracefulShutdown",                     new WebServerGracefulShutdownLifecycle(this.webServer));             getBeanFactory().registerSingleton("webServerStartStop",                     new WebServerStartStopLifecycle(this, this.webServer));         } } 

3) finishBeanFactoryInitialization

finishBeanFactoryInitialization会创建beanFactory中的非lazy bean。

其他处理流程

@Autowired字段 什么时候注入的

在创建bean(getBean -> createBean -> populateBean)时,通过反射调用构造函数创建完bean实例后,会调用BeanPostProcessor。 其中有一个是 AutowiredAnnotationBeanPostProcessor ,在查找当前类有@Autowired的字段并从beanFactory中查找相关的bean,找到后会注入(也会触发bean实例创建)。

@Override public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) { return postProcessProperties(pvs, bean, beanName); } @Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); try { metadata.inject(bean, beanName, pvs); } catch (BeanCreationException ex) { throw ex; } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex); } return pvs; } 

顺序: 先bean注册;创建bean: 实例化、beanAutowired注入 , PostConstruct , afterPropertiesSet

PostConstruct、afterPropertiesSet什么时候调用的

CommonAnnotationBeanPostProcessor

public CommonAnnotationBeanPostProcessor() { setOrder(Ordered.LOWEST_PRECEDENCE - 3); setInitAnnotationType(PostConstruct.class); setDestroyAnnotationType(PreDestroy.class); ... } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass()); try { metadata.invokeInitMethods(bean, beanName); } catch (InvocationTargetException ex) { throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException()); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Failed to invoke init method", ex); } return bean; } 

postProcessBeforeInitialization会在创建bean之后,调用afterPropertiesSet之前调用

Object doCreateBean() { ... // Initialize the bean instance. Object exposedObject = bean; populateBean(beanName, mbd, instanceWrapper); exposedObject = initializeBean(beanName, exposedObject, mbd); ... } protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { ... // 调用BeanPostProcessorsBeforeInitialization Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } // 调用afterPropertiesSet方法 try { invokeInitMethods(beanName, wrappedBean, mbd); } ... return wrappedBean; } 

DispatcherServlet什么时候注册到tomcat的servlet中的

在使用的bean有依赖DispatcherServlet,会创建Bean org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration.DispatcherServletConfiguration#dispatcherServlet 最后auto configuration也会判断创建DispatcherServlet、DispatcherServletRegistrationBean(在beanFactory中没有dispatcherServlet bean的情况下)

DispatcherServletRegistrationBean实现了ServletContextInitializer接口,在tomcat start前,会把DispatcherServlet动态注入到tomcat ServletContext中

tomcat start前调用onStartup

@Override public final void onStartup(ServletContext servletContext) throws ServletException { String description = getDescription(); if (!isEnabled()) { logger.info(StringUtils.capitalize(description) + " was not registered (disabled)"); return; } register(description, servletContext); } @Override protected final void register(String description, ServletContext servletContext) { D registration = addRegistration(description, servletContext); if (registration == null) { logger.info(StringUtils.capitalize(description) + " was not registered (possibly already registered?)"); return; } configure(registration); } @Override protected ServletRegistration.Dynamic addRegistration(String description, ServletContext servletContext) { String name = getServletName(); return servletContext.addServlet(name, this.servlet); } 

Filter怎么注入到tomcat中的

Filter可以通过给Filter标注@Service或创建FilterRegistrationBean的Bean增加Filter。

在创建WebServer的时候,要把Servlet和Filter都生成创建好注册到ServletContext中

createWebServer.tag("factory", factory.getClass().toString()); this.webServer = factory.getWebServer(getSelfInitializer()); private void selfInitialize(ServletContext servletContext) throws ServletException { prepareWebApplicationContext(servletContext); registerApplicationScope(servletContext); WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext); for (ServletContextInitializer beans : getServletContextInitializerBeans()) { beans.onStartup(servletContext); } } protected Collection<ServletContextInitializer> getServletContextInitializerBeans() { return new ServletContextInitializerBeans(getBeanFactory()); } 
@SafeVarargs @SuppressWarnings("varargs") public ServletContextInitializerBeans(ListableBeanFactory beanFactory, Class<? extends ServletContextInitializer>... initializerTypes) { this.initializers = new LinkedMultiValueMap<>(); this.initializerTypes = (initializerTypes.length != 0) ? Arrays.asList(initializerTypes) : Collections.singletonList(ServletContextInitializer.class); // 继承于ServletContextInitializer的bean都被获取出来 addServletContextInitializerBeans(beanFactory); // 类型为Servlet和Filter的Bean也添加到ServletContextInitializer列表中,进而调用onStartup注册到ServletContext中。 addAdaptableBeans(beanFactory); List<ServletContextInitializer> sortedInitializers = this.initializers.values().stream() .flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE)) .collect(Collectors.toList()); this.sortedList = Collections.unmodifiableList(sortedInitializers); logMappings(this.initializers); } 
protected void addAdaptableBeans(ListableBeanFactory beanFactory) { MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory); addAsRegistrationBean(beanFactory, Servlet.class, new ServletRegistrationBeanAdapter(multipartConfig)); addAsRegistrationBean(beanFactory, Filter.class, new FilterRegistrationBeanAdapter()); for (Class<?> listenerType : ServletListenerRegistrationBean.getSupportedTypes()) { addAsRegistrationBean(beanFactory, EventListener.class, (Class<EventListener>) listenerType, new ServletListenerRegistrationBeanAdapter()); } } 

HandlerMapping什么时候注册的

RequestMappingHandlerMapping bean

public void afterPropertiesSet() { ... super.afterPropertiesSet(); } 

AbstractHandlerMethodMapping

@Override public void afterPropertiesSet() { initHandlerMethods(); } protected void initHandlerMethods() { 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); } 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); } } if (beanType != null && isHandler(beanType)) { detectHandlerMethods(beanName); } } // detectHandlerMethods只会读取class信息,并不会主动触发bean创建 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<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> { try { 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)); } methods.forEach((method, mapping) -> { Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); registerHandlerMethod(handler, invocableMethod, mapping); }); } } 

@Lazy的效果

某个bean标注为@Lazy时,在preInstantiateSingletons阶段会跳过这些bean,但是如果一个非@Lazy的bean在创建bean实例的时候,也会创建它依赖的bean。

springboot/mvc/tomcat请求处理流程

tomcat接收到请求,分配给ApplicationFilterChain, ApplicationFilterChain中会先依次调用Filter.doFilter方法,按序执行所有的Filter。Filter都调用完后,交给spring的DispatcherServlet.doService(HttpServletRequest request, HttpServletResponse response);

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { ... // 从RequestMapping registry中找到request对应的MappedHandler // Determine handler for the current request. mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // 转换成HandlerAdapter // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); ... // HandlerInterceptor.preHandle if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. // 调用handlerMethod mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); applyDefaultViewName(processedRequest, mv); // HandlerInterceptor.postHandle mappedHandler.applyPostHandle(processedRequest, response, mv); } ... // 包含ExceptionHandler的调用 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { for (HandlerMapping mapping : this.handlerMappings) { HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; } protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List<Match> matches = new ArrayList<>(); 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()) { Match bestMatch = matches.get(0); if (matches.size() > 1) { Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); matches.sort(comparator); ... } request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod()); handleMatch(bestMatch.mapping, lookupPath, request); return bestMatch.getHandlerMethod(); } else { return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request); } } 

RequestParam解析

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,             Object... providedArgs) throws Exception { MethodParameter[] parameters = getMethodParameters(); if (ObjectUtils.isEmpty(parameters)) { return EMPTY_ARGS; } Object[] args = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { MethodParameter parameter = parameters[i]; parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); args[i] = findProvidedArgument(parameter, providedArgs); if (args[i] != null) { continue; } if (!this.resolvers.supportsParameter(parameter)) { throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver")); } try { args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); } catch (Exception ex) { // Leave stack trace for later, exception may actually be resolved and handled... if (logger.isDebugEnabled()) { String exMsg = ex.getMessage(); if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) { logger.debug(formatArgumentError(parameter, exMsg)); } } throw ex; } } return args; } 

ResponseBody json序列化

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); ... try { this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(formatErrorForReturnValue(returnValue), ex); } throw ex; } } 

RequestResponseBodyMethodProcessor负责 @RequsetBody @ResponseBody(@RestController)中json参数结果的转换 最终MappingJackson2HttpMessageConverter会完成结果的转换

@Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { mavContainer.setRequestHandled(true); ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); // Try even with null return value. ResponseBodyAdvice could get involved. writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
全部评论

相关推荐

昨天 19:38
已编辑
黄冈师范学院 后端
寿命齿轮:实习就一段还拉了,项目一看就不是手搓,学历也拉了,技术栈看着倒是挺好,就是不知道面试表现能咋样。 不过现在才大三,争取搞两端大厂实习,或者一个纯个人项目+一段大厂,感觉秋招还是未来可期。
投递美团等公司10个岗位
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务