目录
理解 Spring web MVC 架构的演变
认识 Spring Web MVC
传统时代的 Spring Web MVC
新时代 Spring Web MVC
SpringBoot 简化 Web MVC 开发
自动装配
条件装配
外部化配置
本章源码下载
理解 Spring Web MVC 架构的演变
基础 Servlet 架构
核心架构: 前端控制器
Spring Web MVC 架构
认识 Spring Web MVC
传统时代的 Spring Web MVC
怎么讲呢? 就是很传统的使用 Spring Framework Web MVC 的方式, 例如 Bean 配置在 xml 中, 前端控制器配置在 Web.xml 中等.
Maven 依赖
- <dependencies>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-Web</artifactId>
- <version>5.1.3.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-webmvc</artifactId>
- <version>5.1.3.RELEASE</version>
- </dependency>
- </dependencies>
Web.xml
- <servlet>
- <servlet-name>dispatcherServlet</servlet-name>
- <servlet-class>org.springframework.Web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:spring.xml</param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>dispatcherServlet</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
Spring.xml
- <context:component-scan base-package="com.jimisun.web"/>
- <mvc:annotation-driven/>
- <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>
- Controller
- @Controller
- public class HelloSpringController {
- @RequestMapping("")
- public String index(){
- return "index";
- }
- }
新时代 Spring Web MVC
所谓的新时代相比肯定是在传统时代上的升级. 提到升级我们首先会想到会提升使用的便捷程度以及性能.
基于注解驱动配置 Web MVC
自动装配前端控制器
基于注解驱动配置 Web MVC
- @Configuration
- @EnableWebMvc
- public class WebDispatcherServletConfigure implements WebMvcConfigurer {
- @Bean
- public ViewResolver viewResolver() {
- InternalResourceViewResolver resourceViewResolver = new InternalResourceViewResolver();
- resourceViewResolver.setViewClass(JstlView.class);
- resourceViewResolver.setPrefix("/WEB-INF/jsp/");
- resourceViewResolver.setSuffix(".jsp");
- return resourceViewResolver;
- }
- }
在 Spring.xml 文件中则不用再配置处理器映射器, 处理器适配器和内部资源视图解析器 (JSP). 只需要保留 < context:component-scan base-package="com.jimisun.web"/> 以便发现我们自定义的前端控制器配置类 WebDispatcherServletConfigure. 因为 @EnableWebMvc 注解为我们自动配置内部资源视图解析器不符合我们自定义的要求, 所以上述代码中我们使用 @Bean 注解重新装配了 InternalResourceViewResolver 类.
基于注解驱动配置的重点是 @EnableWebMvc 注解, 此模块注解将导入 DelegatingWebMvcConfiguration 配置类, 该类又集成了 WebMvcConfigurationSupport 类. WebMvcConfigurationSupport 中则配置了一些关于 Web MVC 的相关 Bean; 例如: RequestMappingHandlerMapping,ContentNegotiationManager,HandlerMapping,BeanNameUrlHandlerMapping,RequestMappingHandlerAdapter,ViewResolver 等等......
自动装配前端控制器
原理 : 在 Web 容器启动时为提供给第三方组件机会做一些初始化的工作, 例如注册 servlet 或者 filtes 等, servlet 规范中通过 ServletContainerInitializer 实现此功能. 每个框架要使用 ServletContainerInitializer 就必须在对应的 jar 包的 META-INF/services 目录创建一个名为 javax.servlet.ServletContainerInitializer 的文件, 文件内容指定具体的 ServletContainerInitializer 实现类, 那么, 当 Web 容器启动时就会运行这个初始化器做一些组件内的初始化工作. 一般伴随着 ServletContainerInitializer 一起使用的还有 HandlesTypes 注解, 通过 HandlesTypes 可以将感兴趣的一些类注入到 ServletContainerInitializerde 的 onStartup 方法作为参数传入.
我们从 spring-Web 的依赖包中找到这个文件, 所以我们可以将前端控制器在 Servlet 容器启动的时候将 Spring Web MVC 的前端控制器添加入 Servlet 容器中, 而不用再配置在 Web.xml 文件中.
我们可以看一下 Spring 的这个 SpringServletContainerInitializer 类
- @HandlesTypes(WebApplicationInitializer.class)
- public class SpringServletContainerInitializer implements ServletContainerInitializer {
- ......
- }
我们可以看到 Spring 定义的这个类实现了 Servlet3.0 的 ServletContainerInitializer 接口, 并且标注了 @HandlesTypes; 表示将实现 WebApplicationInitializer.class 接口的类注入到 ServletContainerInitializer 的回调方法 onStartup() 进行初始化.
我们从上面图可以看到 WebApplicationInitializer 接口的实现类共有四个, 所以就意味着我们自定义一个类实现这三个抽象方法其中的一个就行. 下面是我们自定义的 Servlet 容器初始化器类.
- public class DefaultAnnotationConfigDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
- protected Class<?>[] getRootConfigClasses() {
- return new Class[0];
- }
- protected Class<?>[] getServletConfigClasses() {
- return new Class[]{DispathcherConfig.class};
- }
- protected String[] getServletMappings() {
- return new String[]{"/"};
- }
- }
getServletMappings() 方法用来返回前端控制器要拦截的路径形式. 其中 getRootConfigClasses() 方法用于配置 Spring Framework 与 Service,response 有关的 Bean; 而 getServletConfigClasses() 方法则用来配置 Spring Framework 中的 Web 层相关的 Bean. 资料参考 :
总的来说只要自定义一个类, 实现 WebApplicationInitializer 接口即可; 我们就可以不用在 Web.xml 中配置前端控制器了.
SpringBoot 简化 Web MVC 开发
Spring Boot 从一下三个方面来简化 Web 开发; 分别是 "自动装配","条件装配","外部化配置" 三个方面来简化 Web MVC 开发.
自动装配
SpringBooot 对于 Web MVC 的完全自动装配主要体现在一下三个方面.
前端控制器自动装配
org.springframework.boot.autoconfigure.Web.servlet.DispatcherServletAutoConfiguration,\
Web MVC 相关组件自动装配
org.springframework.boot.autoconfigure.Web.servlet.WebMvcAutoConfiguration,\
Web 容器自动装配
org.springframework.boot.autoconfigure.Web.servlet.ServletWebServerFactoryAutoConfiguration,\
条件装配
从完全自动装配可以看到, SpringBoot 替我们装配了很多东西; 但是在大部分情况下就是基于条件进行装配的, 既满足某某条件才会进行装配. 还是来看一下前端控制器自定装配类 org.springframework.boot.autoconfigure.Web.servlet.DispatcherServletAutoConfiguration,\
- @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
- @Configuration
- @ConditionalOnWebApplication(type = Type.SERVLET)
- @ConditionalOnClass(DispatcherServlet.class)
- @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
- public class DispatcherServletAutoConfiguration {
- }
从该类的注解上我们可以知道 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) 该类的装配顺序,@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class) 在 Web 容器装配之后再进行装配,@Configuration 可被管理的 Bean,@ConditionalOnWebApplication(type = Type.SERVLET) 满足条件为 Web 类型应用,@ConditionalOnClass(DispatcherServlet.class) 满足条件存在 DispatcherServlet 类.
可以看到我们需要满足两个条件 SpringBoot 才会为我们装配这个前端控制器 DispatcherServlet 类.
外部化配置
关于 Web MVC 的外部化配置我们需要了解一下 WebMvcProperties 类和 ResourceProperties 类; 分别对 WebMvc 和资源文件进行配置.
- @ConfigurationProperties(prefix = "spring.mvc")
- public class WebMvcProperties {
- .......
- }
- @ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
- public class ResourceProperties {
- ......
- }
从注解上我们可以了解到, 我们可以在 application.properties 文件或者 application.YAML 文件中进行相关配置.
例如: SpringBoot 在自动装配 Web MVC 组件的时候装配了一个内部资源视图解析器 (JSP)
- @Bean
- @ConditionalOnMissingBean
- public InternalResourceViewResolver defaultViewResolver() {
- InternalResourceViewResolver resolver = new InternalResourceViewResolver();
- resolver.setPrefix(this.mvcProperties.getView().getPrefix());
- resolver.setSuffix(this.mvcProperties.getView().getSuffix());
- return resolver;
- }
其中 this.mvcProperties.getView().getPrefix() 就是从 application.properties 文件或者 application.YAML 文件中获取的值进行的操作而非硬编码.
本章源码下载
传统 Spring Web MVC 的构建环境
基于注解的 Spring Web MVC 环境
完全自动装配的 Spring Web MVC 环境
SpringBoot 示例应用环境
该教程所属 Java 工程师之 SpringBoot 系列教程, 本系列相关博文目录 Java 工程师之 SpringBoot 系列教程前言 & 目录