我们除了使用Xml文件配置之外,还可以使用注解+配置类的方式代替web,xml和SpringMVC的配置文件,来实现Spring MVC的配置工作。

1.使用初始化类替代web.xml

我们知道,Spring MVC 本质就是对 Servlet 的进一步封装,其核心组件是一个 DispatcherServelt。DispatcherServelt 是 Spring MVC 中请求最先到达的地方,负责请求在其他各个组件间的传递和加工。在此之前,像 DispatcherServlet 这样的 Servlet,我们都是通过 web.xml 文件来进行配置的。

除了 web.xml 外,我们还可以通过初始化类来实现对 DispatcherServlet 的配置。Servlet 容器在启动时,会自动查找类项目路径下实现了 javax.servlet.ServletContainerInitializer 接口的初始化类。若找到,则使用该初始化类代替 web.xml,对 Servlet 容器的上下文进行配置。

Spring 就为 ServletContainerInitializer 接口提供了一个名为 SpringServletContainerInitializer 的实现类,其部分源码如下。

@HandlesTypes({WebApplicationInitializer.class})
public class SpringServletContainerInitializer implements ServletContainerInitializer {
    public SpringServletContainerInitializer() {
    }

    public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
        ……
    }
}

我们看到,SpringServletContainerInitializer 类上使用了一个 @HandlesTypes 注解,该注解能够获取到所有实现了 WebApplicationInitializer 接口的类,然后赋值给 onStartup() 方法的 webAppInitializerClasses 参数。onStartup() 方法会借助 webAppInitializerClasses 参数调用 WebApplicationInitializer 实现类中的方法,以实现对 DispatcherServlet 和 Spring MVC 的配置工作。

Spring 提供了一个 DispatcherServelt 的快速配置类 org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer,它就是 WebApplicationInitializer 的实现类之一 ,其常用方法如下表。

方法

说明

protected abstract Class<?>[] getRootConfigClasses();

该方法用于设置 Spring 的配置类。

protected abstract Class<?>[] getServletConfigClasses();

该方法用于设置 Spring MVC 的配置类。

protected abstract String[] getServletMappings();

该方法用于指定 DispatcherServelt 的映射规则,即 web.xml 中的 url-pattern。

protected Filter[] getServletFilters()

该方法用于添加各种过滤器(filter)。

如果我们自定义的初始化类继承了 AbstractAnnotationConfigDispatcherServletInitializer 并将其部署到 Servlet 容器中,Servvelt 容器会自动加载这个初始化类,并使用它来完成对 DispatcherServlet 和 Spring MVC 的配置工作,示例代码如下。

package com.example.annotation.config;

import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import javax.servlet.Filter;

public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
//    设置Spring的配置类
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }
//    设置Spring MVC的配置类
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] {WebConfig.class};
    }
//   为DispatchServlet指定映射规则,相当于web.xml种配置的utl-pattern.
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
//    添加过滤器
    protected Filter[] getServletFilter(){
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("UTF-8");
        characterEncodingFilter.setForceResponseEncoding(true);
        HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
        return new Filter[]{hiddenHttpMethodFilter};
    }
}

2. 使用配置类代替 Spring 的配置文件

我们还可以使用一个标注了 @Configuration 注解的 Java 类(通常被称为“配置类”),来代替 Spring 的配置文件。

在这个配置类中,我们可以定义多个被 @Bean 注解修饰的方法,这些方法与 Spring 配置文件中 标签的作用一样,都是可以将指定的 Java 对象以 Bean 的形式交由 Spring 的 IoC 容器管理。
SpringConfig配置类:

package com.example.annotation.config;

import com.example.annotation.bean.Student;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SpringConfig {

    //定义 Bean
    @Bean
    public Student student(){
        Student student = new Student();
        student.setId(1);
        student.setName("小明");
        student.setAge(18);
        return student;
    }
}

在配置类中,@Bean 注解修饰的方法说明如下:
方法名相当于 标签的 id 属性。
方法的返回值类型就相当于 标签的 class 属性。
若该方中存在参数,则该参数对象通常为 Spring 容器中的组件,Spring 会按照类型或参数名称注入该参数对象。

使用配置类代替 Spring MVC 的配置文件

我们还可以使用一个 @Configuration 注解的 Java 类(通常被称为“配置类”),来代替 Spring MVC 的配置文件。

我们知道,Spring MVC 的配置项繁多,例如组件扫描、视图解析器、拦截器、类型转换器、异常解析器、文件上传解析器等。它们在配置类中的配置方式也不尽相同,大致可以被分为 3 种方式:

实现 WebMvcConfigurer 接口

使用 @EnableWebMvc、@ComponentScan 等注解
使用 @Bean 注解
实现 WebMvcConfigurer 接口
我们可以通过一个实现了 WebMvcConfigurer 接口的配置类(标注 @Configuration 的类)对 Spring MVC 的部分组件进行配置,例如拦截器、格式化程序、视图控制器等。

SpringBoot 1.5 及以前是通过继承 WebMvcConfigurerAdapter 抽象类来定制 Spring MVC 配置的,但在 SpringBoot 2.0 后,WebMvcConfigurerAdapter 抽象类就被弃用了,改为实现 WebMvcConfigurer 接口来定制 Spring MvVC 配置。

WebMvcConfigurer 是一个基于 Java 8 的接口,该接口定义了许多与 Spring MVC 相关的方法,其中大部分方法都是 default 类型的且都是空实现。因此我们只需要定义一个配置类实现 WebMvcConfigurer 接口,并重写相应的方法便可以实现对 Spring MVC 的配置。

方法

说明

default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {}

将静态文件交给 Servlet 容器(Tomcat)内置的默认 Servlet 处理。

default void addInterceptors(InterceptorRegistry registry) {}

添加 Spring MVC 拦截器,对请求进行拦截处理。

default void addResourceHandlers(ResourceHandlerRegistry registry) {}

添加或修改静态资源(例如图片,js,css 等)映射;Spring Boot 默认设置的静态资源文件夹就是通过重写该方法设置的。

default void addViewControllers(ViewControllerRegistry registry) {}

主要用于实现无业务逻辑跳转,例如主页跳转,简单的请求重定向,错误页跳转等

default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {}

用于配置默认的消息转换器(转换 HTTP 请求和响应)。

default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {}

直接添加消息转换器,会关闭默认的消息转换器列表;

实现该方法即可在不关闭默认转换器的起提下,新增一个自定义转换器。
default void configureHandlerExceptionResolvers(List resolvers) {} 配置异常解析器。

使用 @EnableWebMvc、@ComponentScan 等注解

我们还可以在配置类中通过 @EnableWebMvc、@ComponentScan 等注解实现对 Spring MVC 的配置。

  1. 使用 @ComponentScan 注解开启组件扫描
    配置xml
<!--开启组件扫描-->
<context:component-scan base-package="net.biancheng.c"></context:component-scan>

设置配置类

@Configuration
//扫描组件
@ComponentScan("net.biancheng.c")
public class WebConfig implements WebMvcConfigurer {
}
  1. 使用@EnableWebMvc注解开启Spring MVC注解驱动
    我们可以在 Spring MVC 配置类上使用 @EnableWebMvc 注解代替 <mvc:annotation-driven /> 标签,开启 Spring MVC 的注解驱动,示例代码如下。
@Configuration
//开启组件扫描
@ComponentScan("net.biancheng.c")
//开启 Spring MVC注解驱动
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
}

使用 @Bean 注解

我们还可以在配置类中通过 @Bean 注解对 Spring MVC 组件进行配置。

1. 使用 @Bean 注解配置 Thymeleaf 视图解析器

在 Spring MVC 的配置类中,使用 @Bean 注解可以实现对视图解析器的配置。

<!-- 配置 Thymeleaf 视图解析器 -->
<bean id="viewResolver"
      class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
    <property name="order" value="1"/>
    <property name="characterEncoding" value="UTF-8"/>
    <property name="templateEngine">
    <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
        <property name="templateResolver">
        <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
            <!-- 视图前缀 -->
            <property name="prefix" value="/WEB-INF/templates/"/>
            <!-- 视图后缀 -->
            <property name="suffix" value=".html"/>
            <property name="templateMode" value="HTML5"/>
            <property name="characterEncoding" value="UTF-8"/>
        </bean>
        </property>
    </bean>
    </property>
</bean>

从上面的配置内容可以看出,Thymeleaf 视图解析器配置起来还是比较麻烦的,共涉及了 3 种类型的 Bean,它们分别是 ThymeleafViewResolver、SpringTemplateEngine 以及 SpringResourceTemplateResolver。其中 SpringResourceTemplateResolver 的 Bean 是以内部 Bean 的形式,通过 标签注入到 SpringTemplateEngine 类型的 Bean 中的;而 SpringTemplateEngine 的 Bean 又是以内部 Bean 的形式,通过 标签注入到 ThymeleafViewResolver 类型的 Bean 中的。

基于以上情况,我们可以在 Spring MVC 的配置类中,分别定义 3 个不同的 @Bean 注解修饰的方法,代码如下。

@Configuration
//扫描组件
@ComponentScan("net.biancheng.c")
//开启MVC注解驱动
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    //配置生成模板解析器
    @Bean
    public ITemplateResolver templateResolver() {
        WebApplicationContext webApplicationContext =
                ContextLoader.getCurrentWebApplicationContext();
        // ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过 WebApplicationContext
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(webApplicationContext.getServletContext());
        templateResolver.setPrefix("/WEB-INF/templates/");
        templateResolver.setSuffix(".html");
        templateResolver.setCharacterEncoding("UTF-8");
        templateResolver.setTemplateMode(TemplateMode.HTML);
        return templateResolver;
    }

    //生成模板引擎并为模板引擎注入模板解析器
    @Bean
    public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        return templateEngine;
    }

    //生成视图解析器并为解析器注入模板引擎
    @Bean
    public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setCharacterEncoding("UTF-8");
        viewResolver.setTemplateEngine(templateEngine);
        return viewResolver;
    }
}

2.使用 @Bean 注解配置文件上传解析器

我们知道,想要实现文件上传功能,就需要对 Spring MVC 的文件上传解析器进行配置

<!--配置文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!--设置上传文件的默认编码格式-->
    <property name="defaultEncoding" value="UTF-8"></property>
    <!--设置允许上传的最大长度-->
    <property name="maxUploadSize" value="10485760"></property>
</bean

如果我们用Spring MVC的配置类就是:

@Configuration
//扫描组件
@ComponentScan("net.biancheng.c")
//开启MVC注解驱动
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    //配置文件上传解析器
    @Bean
    public CommonsMultipartResolver multipartResolver() {
        CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
        commonsMultipartResolver.setDefaultEncoding("UTF-8");
        commonsMultipartResolver.setMaxUploadSize(1024*1024*10);
        return commonsMultipartResolver;
    }
}