# 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
...
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/
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);
}
}
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);
}
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;
}
2
3
4
5
ExecutableArchiveLauncher 构造函数中,会创建createArchive,表示java -jar启动的那个jar包
public ExecutableArchiveLauncher() {
try {
this.archive = this.createArchive();
} catch (Exception var2) {
throw new IllegalStateException(var2);
}
}
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));
}
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);
}
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());
}
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);
}
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);
}
}
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);
}
}
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();
}
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;
}
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);
}
2
3
applicationContextFactory通过webApplicationType判断使用的是AnnotationConfigServletWebServerApplicationContext
AnnotationConfigServletWebServerApplicationContext中有两个字段 reader可以注册bean scanner(ClassPathBeanDefinitionScanner)从classpath中scan出所有的符合条件(@Component等注解、)的bean
public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
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]));
...
}
2
3
4
5
6
7
8
9
10
# refresh
创建好ApplicationContext, prepare完成后后,会调用refreshContext。
AbstractApplicationContext.refresh()
- 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));
}
}
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还没有创建(实例化)
- 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));
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- 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;
}
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;
}
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;
}
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);
}
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());
}
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);
}
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());
}
}
2
3
4
5
6
7
8
9
# HandlerMapping什么时候注册的
RequestMappingHandlerMapping bean
public void afterPropertiesSet() {
...
super.afterPropertiesSet();
}
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);
});
}
}
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);
}
}
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;
}
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;
}
}
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);
2
3
4
5
6
7
8
9
10
11