SpringBoot系列:3.web启动流程简述
本文简要介绍下SpringBoot中,web项目启动时一些重要的流程:
- SpringBoot中用于web的IOC容器启动流程
- HTTP的url是如何和controller中的方法绑定的?
- 常用的web项目配置参数
SpringBoot中用于web的IOC容器启动流程
Spring的核心就是ApplicationContext
,启动流程实际就是调用其子接口ConfigurableApplicationContext
的refresh()
方法。
在Spring中,有一个ConfigurableApplicationContext
的实现类AbstractApplicationContext
,该类中实现了refresh()的流程。SpringBoot默认提供的启动类都是它的子类。
默认情况下,web服务使用的就是AnnotationConfigServletWebServerApplicationContext
,它的父类是ServletWebServerApplicationContext
,也是AbstractApplicationContext
的间接子类。类之间的继承关系如下:
因此,对于web启动流程可以分析ServletWebServerApplicationContext
的refresh()
,一个简化的启动流程如下:
AbstractApplicationContext
中实现的refresh()流程中,包含了两个方法onRefresh()
和finishRefresh()
。
ServletWebServerApplicationContext
就是通过重写这两个方法,实现了对web server的配置和启动。
来看下ServletWebServerApplicationContext
的onRefresh()
和finishRefresh()
-
onRefresh()
中主要是根据配置信息,初始化web Server,默认使用的就是Tomcat
,依赖tomcat-embed-core
- 设置之后,会继续IOC的启动流程,处理项目中的Bean
- 在
refresh()
的最后,会调用finishRefresh()
,并启动Tomcat
,这之后才可以正常处理http请求。
@Override
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
@Override
protected void finishRefresh() {
super.finishRefresh();
WebServer webServer = startWebServer();
if (webServer != null) {
publishEvent(new ServletWebServerInitializedEvent(webServer, this));
}
}
HTTP的url是如何和controller中的方法绑定的?
当提供restful api时,通常会在Controller类上使用@RestController
注解,绑定的方法就是在该注解的处理逻辑中。
简单说下spring中注解的实现原理
在Spring IOC注入流程中会在处理bean的不同阶段,依次调用一些接口的全部实现类,例如InitializingBean
,BeanPostProcessor
等。
SpringBoot中的注解就是通过实现这些接口,在逻辑中判断bean是否持有指定注解,来对bean做特殊处理。
对@RestController
等web注解的处理类主要是RequestMappingHandlerMapping
,该类间接实现了InitializingBean
接口,通过重写afterPropertiesSet
方法实现处理逻辑。
url和方法绑定的具体流程
下面主要看下RequestMappingHandlerMapping
和其父类AbstractHandlerMethodMapping
中对绑定逻辑的实现,主要函数调用流程如下:
可以看到,注册的大部分逻辑是在AbstractHandlerMethodMapping
中,最终会把url和处理方法保存在一个Hashmap中。
下面对方法做简要说明:
-
RequestMappingHandlerMapping.afterPropertiesSet()
- 初始化配置,一些url解析器和解析规则。
-
AbstractHandlerMethodMapping.initHandlerMethods()
和processCandidateBean()
- 从IOC的beans中,筛选出包含
@RestController
等注解的controller bean。
- 从IOC的beans中,筛选出包含
-
AbstractHandlerMethodMapping.detectHandlerMethods(Object handler)
- 检测controller bean,筛选出包含
@PostMapping()
或@GetMapping()
等注解的方法。
- 检测controller bean,筛选出包含
-
AbstractHandlerMethodMapping.MappingRegistry.register(T mapping, Object handler, Method method)
- 初始化并将url和处理方法注册到
MappingRegistry.registry
成员中,实际是个Hashmap
- 初始化并将url和处理方法注册到
通过这个过程完成了url和方法的映射,后续接到http请求后,就会根据映射把请求路由到对应的方法上。
常用的web项目配置参数
spring:
redis:
database: 0
host: localhost
port: 6379
session:
store-type: redis #session的存储方式,集群部署时选择redis在集群中共享session
timeout: 600s #session的过期时间
main:
web-application-type: servlet #web项目的类型,影响使用的ApplicationContext的实现类,非web项目可设置为:none
server:
tomcat:
max-connections: 1024 #最大连接数
accesslog:
enabled: true #开启accesslog,默认是false,要设置为true才会记录accesslog
directory: /var/user-logs/service-logs #保存accesslog的路径
pattern: "%t [%I] %a %r %s (%D ms)" #记录每行log的格式
file-date-format: .yyyy-MM-dd-HH #log文件的划分,默认是每天一个文件,可加上HH设置为按小时分log文件
port: 8999 #服务启动端口
servlet:
context-path: /my-app #url统一前缀
session:
cookie:
name: myjsessionid #保存在cookies中的session的变量名称
以上内容属个人学习总结,如有不当之处,欢迎在评论中指正