关于SSM以及Spring|关于SSM以及Spring boot中对于Spring MVC配置的问题

SSM中 Spring MVC配置 传统的web.xml配置
web.xml

contextConfigLocationclasspath*:applicationContext.xml org.springframework.web.context.ContextLoaderListener encodingFilter org.springframework.web.filter.CharacterEncodingFilter encodingUTF-8 encodingFilter /* SpringMVC org.springframework.web.servlet.DispatcherServlet contextConfigLocationclasspath:spring-mvc.xml SpringMVC /

spring-mvc.xml

基于java配置的方式
现在JavaConfig配置方式在逐步取代xml配置方式。而WebApplicationInitializer可以看做是Web.xml的替代,它是一个接口。通过实现WebApplicationInitializer,在其中可以添加servlet,listener等,在加载Web项目的时候会加载这个接口实现类,从而起到web.xml相同的作用。
SpittrWebAppInitializer 主配置类
//扩展自Abstrac~Initializer的任意类,都会自动地配置Dispatcher-Servlet和Spring应用上下文 //spring的应用上下文会位于程序的Servlet上下文之中 public class SpittrWebAppInitializerextends AbstractAnnotationConfigDispatcherServletInitializer {@Override protected Class[] getServletConfigClasses() { return new Class[] { WebConfig.class }; }//映射“/”,表示会使用默认的Servlet @Override protected String[] getServletMappings() { return new String[] { "/" }; }@Override protected Class[] getRootConfigClasses() { // TODO Auto-generated method stub return null; }@Override protected Filter[] getServletFilters() { final CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter(); encodingFilter.setEncoding("UTF-8"); encodingFilter.setForceEncoding(true); return new Filter[] { encodingFilter }; }}

我们创建的SpittrWebAppInitializer这个类是继承了
AbstractAnnotationConfigDispatcherServletInitializer,其继承关系为:
AbstractAnnotationConfigDispatcherServletInitializer extends AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer implements WebApplicationInitializer

AbstractDispatcherServletInitializer对DispatcherServlet进行了自动配置和初始化;AbstractContextLoaderInitializer初始化和配置了Spring应用的上下文。因此,任意继承自这个类的类都会通过创建DispatcherServlet和ContextLoaderListener,自动配置DispatcherServlet和Spring应用上下文,但是真正完成配置上下文的是WebApplicationInitializer接口。
WebApplicationInitializer接口 WebApplicationInitializer接口是如何完成配置的呢?其只有一个方法onStartup,看不出什么头绪。但是,在这个包下有另外一个类,SpringServletContainerInitializer。
public interface WebApplicationInitializer { void onStartup(ServletContext servletContext) throws ServletException; }

@HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerInitializer { @Override public void onStartup(Set> webAppInitializerClasses, ServletContext servletContext) throws ServletException {List initializers = new LinkedList(); if (webAppInitializerClasses != null) { for (Class waiClass : webAppInitializerClasses) { // Be defensive: Some servlet containers provide us with invalid classes, // no matter what @HandlesTypes says... if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) { try { initializers.add((WebApplicationInitializer) waiClass.newInstance()); } catch (Throwable ex) { throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex); } } } }if (initializers.isEmpty()) { servletContext.log("No Spring WebApplicationInitializer types detected on classpath"); return; }servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath"); AnnotationAwareOrderComparator.sort(initializers); for (WebApplicationInitializer initializer : initializers) { initializer.onStartup(servletContext); } }}

SpringServletContainerInitializer实现了ServletContainerInitializer接口,其在web容器启动时为提供给第三方组件机会做一些初始化的工作,例如注册servlet或者filtes等,servlet规范中通过ServletContainerInitializer实现此功能。每个框架要使用ServletContainerInitializer就必须在对应的jar包的META-INF/services 目录创建一个名为javax.servlet.ServletContainerInitializer的文件,文件内容指定具体的ServletContainerInitializer实现类,那么,当web容器启动时就会运行这个初始化器做一些组件内的初始化工作。
一般伴随着ServletContainerInitializer一起使用的还有HandlesTypes注解,通过HandlesTypes可以将HandlesTypes指定的类或者实现该接口的类注入到SpringServletContainerInitializer的onStartup方法作为参数传入。
Tomcat容器的ServletContainerInitializer机制的实现,主要交由Context容器和ContextConfig监听器共同实现,ContextConfig监听器负责在容器启动时读取每个web应用的WEB-INF/lib目录下包含的jar包的META-INF/services/javax.servlet.ServletContainerInitializer,以及web根目录下的META-INF/services/javax.servlet.ServletContainerInitializer,通过反射完成这些ServletContainerInitializer的实例化,然后再设置到Context容器中,最后Context容器启动时就会分别调用每个ServletContainerInitializer的onStartup方法,并将感兴趣的类作为参数传入。

关于SSM以及Spring|关于SSM以及Spring boot中对于Spring MVC配置的问题
文章图片
image
Spring Web中通常会有两种应用上下文,一种是Spring MVC上下文,这种上下文通过DispatcherServlet加载,对应上边的getServletConfigClasses()方法,另一种上下文是spring容器本身的上下文,就要通过ContextLoaderListerner创建,对应的是方法getRootConfigClasses()
WebConfig.java 类
@Configuration //标明了该类是一个配置类并且会将该类作为一个SpringBean添加到IOC容器内 @EnableWebMvc //通过查看@EnableWebMvc的源码,可以发现该注解就是为了引入一个DelegatingWebMvcConfiguration Java 配置类。并翻看DelegatingWebMvcConfiguration的源码会发现该类似继承于WebMvcConfigurationSupport的类。 @ComponentScan("spitter.web") public class WebConfig extends WebMvcConfigurerAdapter {/** * 配置JSP视图解析器,他会查找jsp文件,在查找的时候 * 他会在视图名称上加一个特定的前缀和后缀 * home的视图——解析成为/WEB-INF/views/home.jsp * @return */ @Bean public ViewResolver viewResolver(){ InternalResourceViewResolver resolver= new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); resolver.setExposeContextBeansAsAttributes(true); return resolver; }/** * 通过调用enable方法,我们要求DispatcherServelet将 * 对静态资源的请求转发到Servlet容器中的默认的Servlet上, * 不是DispatcherServelet本身处理 * @param configurer */ public void configureDefaultServleHandling(DefaultServletHandlerConfigurer configurer){ configurer.enable(); } }

WebConfig中的配置其实就是对应web.xml中spring-mvc.xml的配置。@EnableWebMvc注解内部使用了@Import(DelegatingWebMvcConfiguration.class),其作用是会把WebMvcConfigurationSupport当成配置文件来用,将其中所有标识有@Bean注解的方法配置成bean,这就成了Spring mvc的默认配置。
@Configuration public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite(); @Autowired(required = false) public void setConfigurers(List configurers) { if (!CollectionUtils.isEmpty(configurers)) { this.configurers.addWebMvcConfigurers(configurers); } } ....//省略其他方法 }

DelegatingWebMvcConfiguration继承了WebMvcConfigurationSupport类,其setConfigurers()方法在覆盖父类的方法之前,它会寻找容器中所有的WebMvcConfigurer实现类,将所有WebMvcConfigurer实现类中的配置组合起来,组成一个超级配置(WebMvcConfigurerAdapter是WebMvcConfigurer的实现类)。这样,WebMvcConfigurationSupport中的bean发布时,就会把这所有配置都带上了。
WebMvcConfigurer接口提供的功能如下表所示:
配置接口 接口说明
configurePathMatch 配置HandlerMapping路径匹配参数
configureContentNegotiation 配置路径到请求内容类型转换的相关参数,如.pdf结尾的请求解析成PDF类型或者其它等
configureAsyncSupport 配置异步请求处理相关参数
configureDefaultServletHandling 配置是否需要以下功能:如果一个请求没有被任何Handler处理,那是否使用DefaultServletHttpRequestHandler来进行处理?
addFormatters 增加额外的Converter和Formatter
addInterceptors 增加拦截器
addResourceHandlers 增加处理静态资源的Handler
addCorsMappings 配置跨域请求相关参数
addViewControllers 使用特殊的Controller来处理指定的URL请求;
configureViewResolvers 配置将Controller返回的视图名称转换成视图的视图解析器; 以便进行视图渲染
addArgumentResolvers 添加支持个性化配置Controller的方法参数类型的Resolver。
addReturnValueHandlers 添加支持个性化处理Controller返回数据类型的处理器;
configureMessageConverters 配置消息转换器;
extendMessageConverters 扩展消息转换器
configureHandlerExceptionResolvers 配置异常处理器
extendHandlerExceptionResolvers 扩展异常处理器
注意: spring-webmvc 从5.0开始已经废除了WebMvcConfigurerAdapter类,对于spring mvc的配置可以通过直接实现WebMvcConfigurer接口来实现。public class WebConfig implements WebMvcConfigurer

Spring boot
在spring boot中通过WebMvcAutoConfiguration自动配置类已经将配置的大部分工作完成了,可以简单的认为,WebMvcAutoConfiguration完成了之前SpittrWebAppInitializer和WebConfig的工作,提供适用于多数应用的自动配置功能。自动配置添加了以下特性:
  1. 引入ContentNegotiatingViewResolver和BeanNameViewResolver beans。
  2. 对静态资源的支持,包括对WebJars的支持。
  3. 自动注册Converter,GenericConverter,Formatter beans。
  4. 对HttpMessageConverters的支持。
  5. 自动注册MessageCodeResolver。
  6. 对静态index.html的支持。
    如果想了解详细信息参考:https://blog.csdn.net/qq_26000415/article/details/78998669
一般情况下是不需要改动mvc的配置的,但是如果需要添加其他mvc配置,有两种方法:
  1. 【关于SSM以及Spring|关于SSM以及Spring boot中对于Spring MVC配置的问题】全面弃用spring boot的自动配置
    1. 直接继承WebMvcConfigurationSupport在扩展的类中重写父类的方法
    2. 使用注解@Configuration + @EnableWebMvc,并继承WebMvcConfigurationAdapter,重写父类的方法
  2. 在spring boot自动配置的基础上添加部分配置
    继承WebMvcConfigurationAdapter,在扩展的类中重写父类的方法
注意: spring boot 从2.0使用spring-webmvc 5.0因此继承WebMvcConfigurationAdapter需要替换为实现WebMvcConfigurer接口 public class WebConfig implements WebMvcConfigurer

    推荐阅读