9.1 扩展视图解析器
对于SpringMVC的自动配置,官网学习文件是这么说的:
以上文档可知,自动配置帮我们配置了原有的视图解析器、静态资源访问路径、首页等。最后红框内是说,如果单单要接管上面的某一个配置,那么可以通过定义一个配置类MyConfig (名字随意),使他实现WebMvcConfiguer 接口,并在类上加上@Configuration注解,不要加@EnableWebMvc 注解(后加上该注解将全面接管所有配置了,而不是单个接管某一个配置),这样我们就可以在MyConfig 类中写自定义配置了。
MyConfig类如下:
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
}
这样配置类就写好了,但是我们还没有写内容,指明我们要自定义哪一个配置。这里我们以自定义一个视图解析器为例,写一个自定义视图解析器的配置类。从官方文档中我们得知,SpringBoot 自动配置了 ContentNegotiatingViewResolver 解析器,那么我们自己定义视图解析器,就要看看 ContentNegotiatingViewResolver 类它实现了什么关于视图解析器的接口,然后我们依葫芦画瓢。
双击 shift 全局搜索 ContentNegotiatingViewResolver,第一行程序如下:
public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered, InitializingBean
就是说这个SpringBoot 自动配置的解析器类 实现 一个接口 ViewResolver,这个名字一看就是跟视图解析器有关的,实现这个接口的类就是一个视图解析器了!现在我们进入这个接口,看看他有什么方法要被实现类重写:
public interface ViewResolver {
@Nullable
View resolveViewName(String viewName, Locale locale) throws Exception;
}
因此 ContentNegotiatingViewResolver 里有一个 resolveViewName 方法:
...
@Nullable
public View resolveViewName(String viewName, Locale locale) throws Exception {
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());
if (requestedMediaTypes != null) {
List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);
View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);
if (bestView != null) {
return bestView;
}
}
...
即会用 getCandidateViews 方法获取候选视图解析器,即存在的所有试图解析器,getCandidateViews里将存在的视图解析器均放到了list集合里(自定义的和原本就配置了的),然后选择一个最好的,来把它当作最后的视图解析器。
由于ViewResolver 接口中只有一个方法 resolveViewName,因此我们在配置类中自定义一个静态内部类 MyViewResolver,想让他变成视图解析器,那么直接让他实现 ViewResolver 接口就行!并重写 resolveViewName 方法呀,并把视图解析器加入到bean容器里哦
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Bean
public ViewResolver MyViewResolver(){
return new MyViewResolver();
}
public static class MyViewResolver implements ViewResolver{
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return null;
}
}
}
到此,我们的自定义视图解析器就写好了,可见是要在自动配置类的基础上的!下面我验证下,我的这个自定义的视图解析器有没有被添加到 list 集合。
我们知道所有的请求都会被dispatcherServlet拦截,然后doservice 或其他请求方法都会调用doDispatch 方法,因此我们在 doDispatch 方法前打个断点:
调试应用,访问 localhost:8080
回到控制台,发现程序走到断点处:
点击 this ,找到 ViewResolver:
再次点击断点,将断点取消:
访问请求通过 doDispatch 方法,出现首页(这边情况不唯一):
9.2 @EnableWebMvc 注解
9.2.1 @EnableWebMvc 注解原理
之前我讲到,扩展SpringMVC 的时候,要自定义一个配置类 MyConfig 实现WebMvcConfigurer 接口 ,并且在类上加上 @Configuration 注解是这个类变为一个配置类,但是不加 @EnableWebMvc 这个注解,为什么呢?我来看看这个注解的含义:
双击shift,搜索 EnableWebMvc:
可以发现,给类加上 @EnableWebMvc 这个注解,就是导入了 DelegatingWebMvcConfiguration 类,我们进入这个类:
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
发现这个类继承了 WebMvcConfigurationSupport 这个类。打开 WebMvcAutoConfiguration 自动配置类:
可见springmvc 自动配置类上有一个条件注解,意思是没有后面的那个…support类时,自动配置类才生效,如果有…support类,自动配置类失效!!!自动配置类失效springboot 只有在自定义的MyConfig 中找配置。
而上面说到加上 @EnableWebMvc 注解就是导入DelegatingWebMvcConfiguration 类,而此类又继承了 WebMvcConfigurationSupport类!
换句话说,加上了@EnableWebMvc 注解,自动配置类全体失效,什么首页配置,静态资源访问路径配置等,全部失效!
9.2.2 自动配置类失效测试
假设我们还是要自定义一个视图解析器,定义配置类 MyMvcConfig 实现WebMvcConfigurer接口;自定义一个MyViewResolver 类,实现ViewResolver 接口,重写 resolveViewName 方法;这样自定义配置视图解析器的类就写好了(同9.1)
这时我们在类上加上 @EnableWebMvc注解:
启动应用,浏览器访问 localhost:8080
我之前是设置了首页 index.html的,访问时使用了默认首页,说明首页配置失效!!
我们再测一个视图解析器配置是否失效,在doDispath 方法处打个断点:debug启动:
可见比之前少了一个 ,少的那个就是自动配置类当中的!!
9.3 SpringMVC 扩展总结
扩展SpringMVC 的时候,要自定义一个配置类 MyConfig 实现WebMvcConfigurer 接口 ,并且在类上加上 @Configuration 注解是这个类变为一个配置类。
注:加上@EnableWebMvc 注解----->自动配置类失效