缘由
Spring Framework Web (MVC) 是开发中非常常见的框架,深入研究其技术原理,达到知其然知其所以然。
简述
Spring Framework Web (MVC) 是Spring 推出的简单且灵活的Web框架,目前已支持Servlet 3.0 规范,提供程序化配置,不再使用web.xml来配置servlet,本文主要会介绍配置的启动、请求处理流程。
本文将会根据自己对Spring Framework Web的理解编辑。
启动流程
Spring Mvc的DispatchServlet是一个非常重要的类,启动流程会围绕着DispatchSerlvet的创建和servlet注册进行。
DispatcherServlet 类结构
DispatcherServlet 继承 FrameworkServlet 抽象类
FrameworkServlet 继承 HttpServletBean 抽象类
HttpServletBean 继承 HttpServlet 抽象类
HttpServlet 继承 GenericServlet 抽象类
GenericServlet 继承 Servlet、ServletConfig 接口
Servlet、ServletConfig、GenericServlet、HttpServlet 是 Java Servlet 扩展包中的类,Servlet接口定义一些重要的方法,ServletConfig是一个Servlet配置对象,初始化过程中servlet容器可以传递信息到Servlet;GenericServlet定义一个通用的、协议无关的Servlet,把ServletConfig 和 servlet 关联起来;HttpServlet继承了GenericServlet并实现了Http协议,自定义的Sevlet可以直接继承此类,实现其中的goGet()... 方法进行业务处理,不用关系Http协议相关的细节。
HttpServletBean作为 HttpServlet 的实现类,将servlet的配置参数作为 bean properties,实现方式为:实现init()方法,把init_param 设置为 bean properties,另外调用抽象方法 initServletBean();
FrameworkServlet 将Spring的应用上下文与Servlet进行融合,Spring boot web 中会使用有参构造实例,public FrameworkServlet(WebApplicationContext webApplicationContext)
,webApplication参数不保证已执行 refresh(),此处存在一段容器处理的逻辑 A:
- 若webApplication没有父容器,会从ServletContext 中获取父容器设置为 webApplication的父容器。
- 若webApplication未分配id,此时会为其分配一个id。
- ServletContext 和 ServletConfig 会被委派到 webApplication。
- 调用 postProcessWebApplicationContext() 方法。
- 通过“contextInitializerClasses” init param 或 通过setContextInitializers属性指定的任何ApplicationContextInitializer将会被应用或调用。
- 调用 refresh() 方法。
FrameworkServlet实现initServletBean(),创建WebApplicationContext:
- 从ServletConfig中的 ServletContext中获取父容器。
- 构造方法中的webApplication参数为不为空时,又实现了 ConfigurableWebApplicationContext 接口,就会实现 逻辑 A。
- 若webApplication为空,则会在ServletContext中获取,WebApplicationContext 必须已加载并保存到ServletContext中才可以获取到。
- 若webApplication为空,就会进行创建,并从ServletConfig中的 ServletContext中获取父容器。
- 若没有收到ContextRefreshedEvent事件,就会调用 onRefresh(WebApplicationContext)方法。
DispatcherServlet 作为 FrameworkServlet 的实现类,主要实现 onRefresh() doService() 两个方法,onRefresh()会执行初始化策略initStrategies(ApplicationContext),doService()会执行请求处理逻辑。
以上介绍了DispatchServlet类的组成,有助于了解其功能实现逻辑。
介绍 DispatcherServlet 初始化逻辑initStrategies(ApplicationContext)
- initMultipartResolver(context);
- initLocaleResolver(context);
- initThemeResolver(context);
- initHandlerMappings(context);
- initHandlerAdapters(context);
- initHandlerExceptionResolvers(context);
- initRequestToViewNameTranslator(context);
- initViewResolvers(context);
- initFlashMapManager(context);
其实现逻辑大致上以 context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class) 相似的方式获取对应的实现类,HandlerMapping、HandlerAdapter的逻辑会有一些稍微的差别,增加了一些排序、默认处理等逻辑。
DispatchServlet 会在第一次web请求时由Tomcat触发创建,调用 initStrategies() 逻辑,并调用 doService() 处理请求。
web请求的处理在 doDispatch(request, response) 中进行:
- 获取 HandlerExecutionChain handler处理链
mappedHandler = getHandler(processedRequest);
,循环调用 HandlerMapping 集合mapping.getHandler(request)
, 在 HandlerMapping 实现类 AbstractHandlerMapping.getHandler() 内部执行handler = getHandlerInternal(request)
交给子类查找Handler, 然后执行executionChain = getHandlerExecutionChain(handler, request)
将匹配到的 Interceptor 放到 chain 中。 - 获取 HandlerAdapter
ha = getHandlerAdapter(mappedHandler.getHandler())
, 循环调用 handlerAdapters 集合adapter.supports(handler)
, 在 AbstractHandlerMethodAdapter 类中查找,若 handler 是 HandlerMethod 类型,执行抽象方法 supportsInternal((HandlerMethod) handler)。 - 执行 HandlerExecutionChain 的
mappedHandler.applyPreHandle(processedRequest, response)
方法。 - 调用handler处理请求
ha.handle(processedRequest, response, mappedHandler.getHandler())
- 执行 HandlerExecutionChain 的
mappedHandler.applyPostHandle(processedRequest, response, mv)
方法。
Spring mvc 主要功能类
Handler
HandlerMapping
类说明:接口定义请求和handler对象之间的映射,Spring Mvc框架提供了 BeanNameUrlHandlerMapping 、RequestMappingHandlerMapping,开发者可自定义实现增加自定义的HandlerMapping,通常 handlerMapping 会包装为 HandlerExecutionChain 实例,有可能伴随一些HandlerInterceptor 实例。Dispatcherservlet 会先调用 HandlerInterceptor的preHandle 方法,在调用handler自身的方法。
类作用:定义接口方法:HandlerExecutionChain getHandler(HttpServletRequest request)
AbstractHandlerMapping
类说明:HandlerMapping接口的抽象实现,支持排序、默认handler,handler interceptor、包括基于路径模式的handler interceptor 映射。
类作用:实现 HandlerExecutionChain getHandler(HttpServletRequest request)
接口方法,调用抽象方法 getHanlderInternal()
,将返回的handler和对应的 interceptor 包装为 HandlerExecutionChain 返回。
AbstractHandlerMethodMapping
类说明:AbstractHandlerMapping 的抽象子类,定义请求和HandlerMethod 之间的映射。实现 InitializingBean 接口,在子类作为Bean初始化时,执行 initHandlerMethods(),将所有@Controller @RequestMapping 注解的方法全部解析为HandlerMethod。
类作用:初始化HandlerMethod。
RequestMappingInfoHandlerMapping
类说明:AbstractHandlerMethodMapping 的抽象实现类,使用 RequestMappingInfo 定义请求和Handler之间的映射。
类作用:实现 Handler 与 request 之间的匹配逻辑。
RequestMappingHandlerMapping
类说明:创建 RequestMappingInfo 实例,从@Controller 类中方法级的 @RequestMapping 注解 解析为 RequestMappingInfo 实例。
类作用:创建HandlerMethod 和 request 之间的映射关系
HandlerAdapter
类说明:每种handler类型为了能够处理request,必须实现此接口。DipatcherServlet 访问所有handler都是通过此接口,意味着不必包含handler类型的任何指定代码。
类作用:定义 boolean supports(Object handler) 和 handle() ,DispatcherServlet 选择合适的HandlerAdapter时,通过 supports 方法来判断,选中后执行此adapter的handle().
AbstractHandlerMethodAdapter
类说明:HandlerAdapter的抽象实现,支持 HandlerMethod 类型。
类作用:指定handler type 是 HandlerMethod后,实现了 supports() 逻辑,并定义 handleInternal() 抽象方法给子类实现。
RequestMappingHandlerAdapter
类说明:AbstractHandlerMethodAdapter 的扩展,支持 @RequestMapping 注解的 HandlerMethods.
类作用:实现抽象方法 handleInternal(),定义具体的调用逻辑,并处理参数绑定和返回参数转换。
内置Tomcat的运行机制
Spring web 应用的上下文是 AnnotationConfigServletWebServerApplicationContext,其继承了 ServletWebServerApplicationContext。执行 SpringApplication#applicationContext.refresh() 时,会调用ServletWebServerApplicationContext的refresh(),ServletWebServerApplicationContext间接继承了 抽象类AbstractApplicationContext,所以会执行 AbstractApplicationContext#refresh(),此处重点关注 refresh()中的 onfresh(),ServletWebServerApplicationContext实现了此方法并调用 createWebServer(),至此进入创建WebServer的逻辑。
首先会获取 ServletWebServerFactory 实现类 TomcatServletWebServerFactory,然后执行 ServletWebServerFactory#getWebServer() 方法获取 webServer实例。
-- TomcatServletWebServerFactory Bean定义
ServletWebServerFactoryAutoConfiguration 导入 ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class 注册 WebServerFactoryCustomizerBeanPostProcessor\ ErrorPageRegistrarBeanPostProcessor Bean定义。 WebServerFactoryCustomizerBeanPostProcessor 在Bean初始化之前,若Bean属于WebFactory,就会执行WebServerFactoryCustomizer 实现类的 customize() 方法,属于WebFactory定制化的逻辑。大多数的定制逻辑差不多都是一致的,实现定制接口,并注册为Bean。
ServletWebServerFactoryAutoConfiguration 导入 ServletWebServerFactoryConfiguration.EmbeddedTomcat.class 定义 TomcatServletWebServerFactory Bean。
Tomcat启动
Tomcat的启动过程包括以下步骤:
- 初始化Catalina:在Tomcat类中,会初始化一个Catalina实例。Catalina是Tomcat的核心容器,用于管理各个组件和模块。
- 加载配置文件:Tomcat在启动时需要加载配置文件,通常是server.xml,其中包含了Tomcat服务器的配置信息,如端口号、连接池设置等。这些配置文件会被解析成对应的Java对象,并由Catalina进行管理。
- 创建服务和连接器:Tomcat根据配置文件中的信息创建一个或多个服务(Service)和连接器(Connector)。服务表示Tomcat的一个实例,而连接器用于处理与客户端的连接。每个连接器通常使用一个 独立的线程池来处理客户端请求。
- 初始化组件:Tomcat会初始化一系列组件,包括Engine、Host、Context等。Engine表示整个Tomcat服务器,Host表示一个虚拟主机,Context表示一个Web应用程序上下文。
- 加载Web应用程序:Tomcat在启动时会加载预配置的Web应用程序。这些应用程序通常存储在webapps目录下。Tomcat会为每个应用程序创建一个Context对象,并将其添加到对应的Host中。
- 启动Web应用程序:在Tomcat启动过程中,会初始化并启动预加载的Web应用程序,即调用Web应用程序的init()方法。
- 启动连接器:Tomcat会启动之前创建的连接器,开始监听指定的端口,等待客户端请求的到来。
- 等待请求:Tomcat启动完成后,进入等待状态,等待客户端发送请求。
DispatcherServlet 如何部署到Tomcat当中?
DispatcherServletAutoConfiguration 配置类中有几个子配置类,比如定义DispatcherServlet和MultipartResolver 的 DispatcherServletConfiguration配置类,还有定义 DispatcherServletRegistrationBean 的 DispatcherServletRegistrationConfiguration 配置类,DispatcherServletRegistrationBean负责DispatcherServlet 的部署。
DispatcherServletRegistrationBean 类继承ServletRegistrationBean,在构造方法中调用父类的构造方法和 设置应用请求上下文的addUrlMappings()。
ServletRegistrationBean 类继承 DynamicRegistrationBean,实现父类的抽象方法 addRegistration(ServletContext),执行servletContext.addServlet(name, this.servlet),将DispatcherServlet 注册到 Servlet3.0容器当中。
DynamicRegistrationBean 类继承 RegistrationBean,实现父类的抽象方法 register(String description, ServletContext servletContext),执行抽象方法 addServlet()。register()的执行调用是在 RegistrationBean 的onStartUp() 中进行,此方法也是父类 ServletContextInitializer 的实现。
ServletContextInitializer 接口用于程序化配置Servlet3.0上下文,设计逻辑与 ServletContainerInitializer 相似,但是并不是由Servlet container控制,而是由Spring进行管理,但是又不是与 SCI 完全没有关系,启动Tomcat时,会以ServletWebServerApplicationContext#selfInitialize作为 ServletContextInitializer 的实现设置到 TomcatStarter 对象中,TomcatStarter 则是 ServletContainerInitializer 的子类,以SCI的角色注册到 Tomcat 中,Tomcat启动过程中会执行SCI机制,TomcatStarter的 onStartUp()方法则会执行
public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException {
for (ServletContextInitializer initializer : this.initializers) {
// ServletWebServerApplicationContext#selfInitialize 则会在此调用
initializer.onStartup(servletContext);
}
}
ServletWebServerApplicationContext#selfInitialize 会将Spring中所有ServletContextInitializer子类Bean,遍历调用。
private void selfInitialize(ServletContext servletContext) throws ServletException {
prepareWebApplicationContext(servletContext);
registerApplicationScope(servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
// DispatcherServletRegistrationBean 会将DispacherServlet 动态的注册到 Tomcat 当中
beans.onStartup(servletContext);
}
}
*DispatcherServlet部署到Tomcat的过程中,利用sci、Servlet3.0动态注册Servlet等Servlet相关的技术,另外扩展了 SCI 机制,利用 ServletContextInitializer 接口,加入了Spring特性。
Spring Mvc 配置类
@EnableWebMvc
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
类说明:SpringMvc 基于注解配置的重要类,注解EnableWebMvc可以添加到 @Configuration 注解的类上,可以开启Spring Mvc的自动配置。Spring Bean 实现 WebMvcConfigurer 接口进行自定义Spring Mvc配置,若需要更高级的设置,可使用 WebMvcConfigurationSupport 或者 DelegatingWebMvcConfiguration 同时移除 @EnableWebMvc 注解。
类作用:导入 DelegatingWebMvcConfiguration 配置类。
DelegatingWebMvcConfiguration
类说明:WebMvcConfigurationSupport 的子类,本身作为一个配置类,利用setter注入将WebMvcConfigurer类型的Bean注入到 WebMvcConfigurerComposite 中,由 WebMvcConfigurerComposite 负责在 WebMvcConfigurer 的接口实现方法中,循环调用,WebMvcConfigurerComposite 接口实现方法全部在 DelegatingWebMvcConfiguration 中调用。
类作用:重写 WebMvcConfigurationSupport 方法,并调用 WebMvcConfigurerComposite 方法,实现定制Spring Mvc的逻辑。
补充说明:采用委派模式,收到 WebMvcConfigurationSupport 任务后,交给 WebMvcConfigurerComposite 执行具体调用。
WebMvcConfigurerComposite
类说明:WebMvcConfigurer 的实现类,采用了组合设计模式,实现 WebMvcConfigurer 接口,并内置一个 WebMvcConfigurer 集合属性,在接口实现方法中循环调用,并以WebMvcConfigurer 实现类的身份在 DelegatingWebMvcConfiguration 实现接收调用。
类作用:接收 DelegatingWebMvcConfiguration 任务,执行具体调用。
WebMvcConfigurationSupport
类说明:实现 ApplicationContextAware, ServletContextAware 接口,在子类中以配置类的角色注册到 Spring Ioc 中,并获得 ServletContext、ApplicationContext Bean。提供Java配置 Mvc 的重要类,注册 HandlerMappings HandlerAdapters HandlerExceptionREsolverComposite AntPathMatcher UrlPathHelper。
类作用:Java 配置 Mvc,注册各个功能类到Spring IOC.
补充:
- 自定义SpringMvc配置时,可以通过实现WebMvcConfigurer接口,实现指定的接口即可,启动时会自动搜索其实现类进行处理。另外可通过继承 DelegatingWebMvcConfiguration 或者 WebMvcConfigurationSupport 配置更加高级的参数。
- WebMvcConfigurationSupport 类中注册了 Spring Mvc 所需要的所有组件,可通过继承此类进行扩展。主要分为 HandlerMappings、HandlerAdapters、 HandlerExceptionResolverComposite、AntPathMatche、UrlPathHelper、HttpMessageConverters 等等。
- Spring Boot 中的WebMvcAutoConfiguration可以替换掉@EnableMvc注解,类中的子类 WebMvcAutoConfigurationAdapter 继承了 WebMvcConfigurer, 并导入 EnableWebMvcConfiguration 类,此类继承的是 DelegatingWebMvcConfiguration,覆盖了父类中 Spring Mvc 主要组件的创建,主要是利用Spring boot 获取到的参数传递到组件创建方法。
- Spring Boot 中的WebMvcAutoConfiguration 自动配置顺序在 DispatcherServletAutoConfiguration 之后,DispatcherServletAutoConfiguration 在 ServletWebServerFactoryAutoConfiguration 之后,此顺序可以理解为 先自动配置 内置服务器,再配置 DispatcherServlet,然后才是 WebMvc 的配置。
Spring Mvc DispatcherServlet 注册到Tomcat 相关类。
ServletWebServerFactoryConfiguration
类说明:servlet web servers的配置类,在 ServletWebServerFactoryAutoConfiguration 使用@Import注解导入。
类作用:注册 TomcatServletWebServerFactory 作为Bean。
TomcatServletWebServerFactory
类说明:AbstractServletWebServerFactory 实现类,被用来创建TomcatWebServer,可以被Spring的 ServletContextInitializer 或者 Tomcat LifecycleListeners 初始化。
类作用:创建 WebServer。
核心代码
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
connector.setThrowOnFailure(true);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
// prepareContext() -> configureContext() 创建 TomcatStarter 并设置到TomcatEmbeddedContext.starter中
prepareContext(tomcat.getHost(), initializers);
// 创建 TomcatWebServer 并执行 initialize() -> Tomcat.start() -> StandardServer.start() -> startInternal() -> StandardService.start() -> startInternal() -> StandardEngine.startInternal() - 异步 -> StandardContext.startInternal() -> 循环执行 initializers 中元素的 onStartUp() -> TomcatStarter.onStartup() -> 开始执行 ServletContextInitializer 实现类的 onStartup().
return getTomcatWebServer(tomcat);
}
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#selfInitialize
private void selfInitialize(ServletContext servletContext) throws ServletException {
prepareWebApplicationContext(servletContext);
registerApplicationScope(servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
// 执行 ServletContextInitializer 实现类,比如:DispatcherServletRegistrationBean。
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}
}
ServletWebServerApplicationContext
类说明:AnnotationConfigServletWebServerApplicationContext 会实现此类,实现父类 GenericWebApplicationContext 的 onRefresh() 调用 createWebServer()。
类作用:调用 createWebServer()。
ServletWebServerApplicationContext
类说明:一个 WebApplicationContext,可从容器Bean ServletWebServerFactory 中自动引导。此context 通过搜索一个单独 ServletWebServerFactory bean 来创建、初始化、运行一个web server。另外context中定义的所有Sevlet Filter bean 将会被自动注册到web server中。
类作用:实现onFresh()方法,调用createWebServer().
DispatcherServletConfiguration 注册 DispatcherServlet 到Spring Bean 容器:
DispatcherServletAutoConfiguration {
DispatcherServletConfiguration {
new DispatcherServlet()
}
}
DispatcherServletRegistrationBean
类说明:ServletRegistrationBean子类,负责对DispatcherServlet自动注入,注册并暴露 DispatcherServletPath 信息。
类作用:
- ServletRegistrationBean 是DynamicRegistrationBean子类,实现 addRegistration(ServletContext) 抽象方法,可将自身的servlet添加到web 上下文中(
ervletContext.addServlet(name, this.servlet)
)。 - DynamicRegistrationBean是RegistrationBean的子类,实现 register(ServletContext) 抽象方法,执行 addRegistration() 抽象方法。
- RegistrationBean 是 ServletContextInitializer 的抽象实现类,实现onStartup(ServletContext)接口方法,调用 register() 抽象方法。
总结
Spring Mvc 作为非常常见的技术,对其中的主要逻辑设计学习了解,可以更好的掌控开发。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。