9.扩展SpringMVC(源码警告)

zhanglei 2022年06月14日 293次浏览

9.1 扩展视图解析器

​ 对于SpringMVC的自动配置,官网学习文件是这么说的:

image-20220614163731498

​ 以上文档可知,自动配置帮我们配置了原有的视图解析器、静态资源访问路径、首页等。最后红框内是说,如果单单要接管上面的某一个配置,那么可以通过定义一个配置类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集合里(自定义的和原本就配置了的),然后选择一个最好的,来把它当作最后的视图解析器。

image-20220614171128707

​ 由于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 方法前打个断点:

image-20220614171453214

​ 调试应用,访问 localhost:8080

image-20220614171603987

​ 回到控制台,发现程序走到断点处:

image-20220614171726976

​ 点击 this ,找到 ViewResolver:

image-20220614171928836

​ 再次点击断点,将断点取消:

image-20220614172059471

​ 访问请求通过 doDispatch 方法,出现首页(这边情况不唯一):

image-20220614172220935

9.2 @EnableWebMvc 注解

9.2.1 @EnableWebMvc 注解原理

​ 之前我讲到,扩展SpringMVC 的时候,要自定义一个配置类 MyConfig 实现WebMvcConfigurer 接口 ,并且在类上加上 @Configuration 注解是这个类变为一个配置类,但是不加 @EnableWebMvc 这个注解,为什么呢?我来看看这个注解的含义:

​ 双击shift,搜索 EnableWebMvc:

image-20220614174656663

​ 可以发现,给类加上 @EnableWebMvc 这个注解,就是导入了 DelegatingWebMvcConfiguration 类,我们进入这个类:

public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport 

​ 发现这个类继承了 WebMvcConfigurationSupport 这个类。打开 WebMvcAutoConfiguration 自动配置类:

image-20220614175155860

​ 可见springmvc 自动配置类上有一个条件注解,意思是没有后面的那个…support类时,自动配置类才生效,如果有…support类,自动配置类失效!!!自动配置类失效springboot 只有在自定义的MyConfig 中找配置。

​ 而上面说到加上 @EnableWebMvc 注解就是导入DelegatingWebMvcConfiguration 类,而此类又继承了 WebMvcConfigurationSupport类!

​ 换句话说,加上了@EnableWebMvc 注解,自动配置类全体失效,什么首页配置,静态资源访问路径配置等,全部失效!

9.2.2 自动配置类失效测试

​ 假设我们还是要自定义一个视图解析器,定义配置类 MyMvcConfig 实现WebMvcConfigurer接口;自定义一个MyViewResolver 类,实现ViewResolver 接口,重写 resolveViewName 方法;这样自定义配置视图解析器的类就写好了(同9.1)

​ 这时我们在类上加上 @EnableWebMvc注解:

image-20220614180338382

​ 启动应用,浏览器访问 localhost:8080

image-20220614180527087

​ 我之前是设置了首页 index.html的,访问时使用了默认首页,说明首页配置失效!!

​ 我们再测一个视图解析器配置是否失效,在doDispath 方法处打个断点:debug启动:

image-20220614180821852

​ 可见比之前少了一个 ,少的那个就是自动配置类当中的!!

9.3 SpringMVC 扩展总结

​ 扩展SpringMVC 的时候,要自定义一个配置类 MyConfig 实现WebMvcConfigurer 接口 ,并且在类上加上 @Configuration 注解是这个类变为一个配置类。

​ 注:加上@EnableWebMvc 注解----->自动配置类失效