# 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
                    ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

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/
1
2
3
4

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);
	}
}

1
2
3
4
5
6
7
8
9

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);
}
1
2
3
4
5
6
7
8

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;
}
1
2
3
4
5

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

public ExecutableArchiveLauncher() {
   try {
      this.archive = this.createArchive();
   } catch (Exception var2) {
      throw new IllegalStateException(var2);
   }
}
1
2
3
4
5
6
7
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));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

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);
}
1
2
3
4
5
6

然后用这个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());
}
1
2
3
4
5
6
7
8
9
10

创建好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);
}
1
2
3
4
5
6
7

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);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 我们编写的main方法

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

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
1
2
3
4
5
6
7

# 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();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

后面是正式的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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

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);
}
1
2
3

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);
}
1
2
3
4

# 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]));
   ...
}
1
2
3
4
5
6
7
8
9
10

# 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));
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

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

  1. 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));
		}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  1. 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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

顺序: 先bean注册;创建bean: 实例化、beanAutowired注入 , PostConstruct , afterPropertiesSet。注意factoryBean创建factory要产出的object也就是调用getObject方法是在afterProperties之后的。

# 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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

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;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 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());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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());
   }
}
1
2
3
4
5
6
7
8
9

# HandlerMapping什么时候注册的

RequestMappingHandlerMapping bean

public void afterPropertiesSet() {
   ...
   super.afterPropertiesSet();
}
1
2
3
4

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);
      });
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

# @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);
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

# 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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 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;
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

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);
1
2
3
4
5
6
7
8
9
10
11