探索 SpringBoot (四)SpringMvc 深度解析
文章目录
缘起
闲着无聊 写写博客。
Servlet & Tomcat & SpringMvc
- 什么是 servlet?
简单的来说,Servlet 是Java 提供的Servlet 接口
- 什么是 tomcat ?
简单的来说,tomcat 是实现的Servlet规范的 容器
- 什么是 springmvc ?
简单的来说,springmvc 是spring 推出的实现Servlet规范的 MVC框架
一句话概括他们的联系
用户的请求经过 tomcat , 被封装 HttpServletRequest,经过 dispatcherservlet, 到达用户的 controller, 最后被封装成 HttpServletResponse 经过容器处理 然后响应给用户 (这里面的内容有点多 以后有时间写篇博客分析下)
DispatcherServlet
请求从到达 DispatcherServlet 的时候便正式进入了 springmvc . DispatcherServlet 工作主要分成两部分
1 初始化组件
在 FrameworkServlet 的 initWebApplicationContext --> onRefresh --> initStrategies 进行组件初始化
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
核心组件介绍
基本概念
handler 处理者,可以简单理解成 controller 中的每个方法 就是一个 handler
1 HandlerMappings:
可以理解成一个map , 用于寻找 路径(@RequestMap()中定义的) 所对应的 handle 方法
2 HandlerAdapters:
字面意思 就是一个适配器,看起来好像很难理解我们看看这个接口
public interface HandlerAdapter {
boolean supports(Object handler);
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
long getLastModified(HttpServletRequest request, Object handler);
}
我们再来看看接口实现
SimpleServletHandlerAdapter
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((Servlet) handler).service(request, response);
return null;
}
SimpleControllerHandlerAdapter
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
这下看明白了吧, 就是一个 请求的适配器。定义了一个 handle 接口,让子类去实现请求处理逻辑
3 HandlerExceptionResolver 异常处理的组件 没仔细研究
4 ViewResolver 视图解析 根据 viewName 和 locale 返回视图对象
View resolveViewName(String viewName, Locale locale) throws Exception;
5 MultipartResolver 处理上传请求
- 九大组件可以参考
2 响应处理
组件也简单介绍了下是对HTTP请求进行响应,作为Servlet,Web容器会调用Servlet的doGet()或者doPost()方法,在经过FrameworkServlet的processRequest()简单处理后,会调用DispatcherServlet的doService方法,在这个方法调用中封装了doDispatch() 处理请求
请求流程
1 请求到达 DispatcherServlet, 然后通过 HandlerMapping (默认通过 RequestMappingHandlerMapping)
2 调用 HandlerMapping 的 getHandler 方法得到 handler( HandlerExecutionChain)
3 根据 handler 获取 HandlerAdapter (RequestMappingHandlerAdapter)
4 HandlerAdapter 调用 handle,最后到达我们的 Controller 层
5 Controller 执行程序 返回 ModelAndView
6 调用 processDispatchResult 处理请求
7 最后 调用 View 的 render 渲染
SpringMvc 手动配置 & 自动装配
- 我们来简单回忆下原来的 springmvc 要怎么配置吧
1 配置 DispathcherServlet
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-context.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
2 配置 RequestMappingHandlerMapping RequestMappingHandlerAdapter InternalResourceViewResolver
<context:component-scan base-package="xxx.controller"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
springmvc 实现自动装配
1 实现 AbstractAnnotationConfigDispatcherServletInitializer
相当于上面的 第一步 配置 DispathcherServlet
/**
* Spring Web Mvc 自动装配的实现
*
* Created by jun on 2018/11/26.
*/
public class DefaultAnnotationConfigDispatcherServletInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer {
@Nullable
@Override
protected Class<?>[] getRootConfigClasses() {
// web.xml
return new Class[0];
}
@Nullable
@Override
protected Class<?>[] getServletConfigClasses() {
// dispatcherservlet
return new Class[] {DispatcherServletConfiguration.class};
}
@Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
}
2 实现 WebMvcConfigurer
@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
<!--<bean id="viewResolver" //class="org.springframework.web.servlet.view.InternalResourceViewResolver">-->
// <!--<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>-->
// <!--<property name="prefix" value="/WEB-INF/jsp/"/>-->
// <!--<property name="suffix" value=".jsp"/>-->
// <!--</bean>-->
@Bean
public ViewResolver viewResolver(){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HandlerInterceptor() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截中...");
return true;
}
});
}
}
这里相当于 上文的
InternalResourceViewResolver RequestMappingHandlerAdapter RequestMappingHandlerMapping
但是 我们明明只看到了 InternalResourceViewResolver呀,其余的两个呢
我们看看这个注解 @EnableWebMvc
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
。。。
最后 我们在 DelegatingWebMvcConfiguration 的父类 WebMvcConfigurationSupport 中发现了两个bean
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
adapter.setContentNegotiationManager(mvcContentNegotiationManager());
...
}
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
mapping.setInterceptors(getInterceptors());
}
读到这里,也许你明白了
自动配置 只是用 @Bean 注解的方式,将原来在 xml 中配置的bean ,放在代码中配置
在 SpringBoot 里面的实现
SpringBoot 里面 springmvc 自动装配的实现主要是用到 WebMvcAutoConfiguration 这个类
1 SpringBoot 里 dispatcherServlet 的装配
...
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
...
我们看这行的注解 大概意思是这个类的装配要在
DispatcherServletAutoConfiguration 之后
我们看看 DispatcherServletAutoConfiguration 干了啥
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setDispatchOptionsRequest(
this.webMvcProperties.isDispatchOptionsRequest());
dispatcherServlet.setDispatchTraceRequest(
this.webMvcProperties.isDispatchTraceRequest());
dispatcherServlet.setThrowExceptionIfNoHandlerFound(
this.webMvcProperties.isThrowExceptionIfNoHandlerFound());
dispatcherServlet.setEnableLoggingRequestDetails(
this.httpProperties.isLogRequestDetails());
return dispatcherServlet;
}
我们找到了 dispathcerservlet 的装配
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {
我们再往后看看
ServletWebServerFactoryAutoConfiguration
public class ServletWebServerFactoryAutoConfiguration {
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new ServletWebServerFactoryCustomizer(serverProperties);
}
@Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
大概就是定义了一些容器
- 在上面我们可以看出 DispatcherServletAutoConfiguration 主要是加载和配置了 dispatcherServlet
2 SpringBoot 里 其他组件的装配 的装配
我们在 WebMvcAutoConfiguration 下面的代码中可以看到
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
private final WebMvcProperties mvcProperties;
@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null
|| this.mvcProperties.isIgnoreDefaultModelOnRedirect());
return adapter;
}
@Bean
@Primary
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
// Must be @Primary for MvcUriComponentsBuilder to work
return super.requestMappingHandlerMapping();
}
}
这里无非就是覆盖 DelegatingWebMvcConfiguration 的方法,通过外部化配置。加载了 DelegatingWebMvcConfiguration 加载了 springmvc 的基础组件
总结
我们通过 以下几种方式回忆了下 springmvc
1 手动 xml 配置
2 通过 @EnableWebMvc
3 通过 SpringBoot 的自动装配
其实 SpringBoot 自动装配也不是太难,就是通过一些外部化配置,和 @Bean 注解的方式
践行 约定优于配置。我们做了一些简化。核心还是 spring。