在springmvc3时,对于springmvc的配置(interceptor、viewresolver等)都是通过springmvc的配置文件实现的,springmvc4之后这样可以通过配置类来实现,所以这些配置的方法都放在了WebMvcConfigurer中,我们需要实现这个借口来完成对springmvc的设置,但这个接口里的方法很多,有时我们并不想实现所有方法,于是springmvc提供了一个WebMvcConfigurerAdapter,替我们提高了所有方法的默认实现,我们只需继承这个类,然后通过override相应的方法来设置相应的配置。当然这还不够,因为我们虽然定义了自己的配置类,但还无法把他和他里面的配置加入到springmvc的上下文,于是乎我们还需要添加@configuration(由于它包含@component,所以我们实现的配置类可以被加载到springmvc的上下文,但此时它里面的相关配置还没有加入)和@EnableWebMvc(在一个配置类上加这个就行,不用所以配置类都加),这个注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

可以看到他import了一个类DelegatingWebMvcConfiguration:

@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();


    @Autowired(required = false)
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }
    }

之前我们的配置类已经通过@configuration加入到了spring上下文,所以这里通过@Autowired获得我们的配置类然后把它加入了configurers,接下来我们应该关注DelegatingWebMvcConfiguration的父类WebMvcConfigurationSupport,它里面的大部分方法都被@bean注释,也就是说在bean扫描的时候会调用这些方法创建相应的bean,这时他的方法有会去调用DelegatingWebMvcConfiguration里的方法进而调用我们的配置类里的方法以至于使我们的配置加载到spring中,举个例子,比如mvcViewResolver这个方法,bean扫描时会被调用,它会最终调用到我们的配置类里configureViewResolvers方法(如果我们有需要实现的话,否则他是个空方法),在该方法里我们可以创建自己想要的viewresolver,然后调用ViewResolverRegistry.viewResolver()方法把我们的viewresolver加入集合,然后由mvcViewResolver把我们的viewresolver加载到了spring的上下文以供后续使用。 所以说@EnableWebMvc很重要,但在springboot里,springboot为我们提供了自动配置类WebMvcAutoConfiguration,此时他会提供一些springmvc的默认配置,也就是说它的内部类WebMvcAutoConfigurationAdapter也通过实现WebMvcConfigurerAdapter来添加配,同时它还提供了一个内部类EnableWebMvcConfiguration,他是DelegatingWebMvcConfiguration的子类,这时我们会发现它可以取代@EnableWebMvc的作用了,所以在springboot中,我们写配置类的话不用再加@EnableWebMvc了,因为springboot已经为我们加载了DelegatingWebMvcConfiguration,但如果你加了@EnableWebMvc,那springboot的mvc的自动配置就废了,因为:

@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
        WebMvcConfigurerAdapter.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
        ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {


可以看到红色字体,就能找到答案,因为加了@EnableWebMvc,导致spring上下文中就有了WebMvcConfigurationSupport.class这个类型的bean,所以mvc的自动配置就废了。


当然有些配置不用去实现WebMvcConfigurer里的方法也可以配置,比如ViewResolver,我们可以类似下面这样也可以,springboot就是这么做滴

        @Bean
        @ConditionalOnMissingBean
        public InternalResourceViewResolver defaultViewResolver() {
            InternalResourceViewResolver resolver = new InternalResourceViewResolver();
            resolver.setPrefix(this.mvcProperties.getView().getPrefix());
            resolver.setSuffix(this.mvcProperties.getView().getSuffix());
            return resolver;
        }


其实对于webmvc的配置最重要的类就是WebMvcConfigurationSupport,他里面被标记为bean的方法都会被调用,恰恰就是在这些方法中做了webmvc的配置

再举个例子

如果我们想直接在controller不做操作,只是想返回一个字符串,这个字符串应该是一个view的名字,此时就可以在我们实现的WebMvcConfigurerAdapter中调用addViewControllers,配置url和对应的view名即可。他的原理是在WebMvcConfigurationSupport中

@Bean
    public HandlerMapping viewControllerHandlerMapping() {
        ViewControllerRegistry registry = new ViewControllerRegistry();
        addViewControllers(registry);

        AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
        handlerMapping = (handlerMapping != null ? handlerMapping : new EmptyHandlerMapping());
        handlerMapping.setPathMatcher(mvcPathMatcher());
        handlerMapping.setUrlPathHelper(mvcUrlPathHelper());
        handlerMapping.setInterceptors(getInterceptors());
        handlerMapping.setCorsConfigurations(getCorsConfigurations());
        return handlerMapping;
    }

这里的addViewControllers最终会调用到我们的实现类里的那个addViewControllers方法。然后registry.getHandlerMapping会创建一个SimpleUrlHandlerMapping,注册到spring上下文中,在springmvc中有大概四种HandlerMapping,包括常用的requestmappingHandlerMapping,还有前面提到的SimpleUrlHandlerMapping,其实都是以不同的方式来维护url与controller的对应关系。这里SimpleUrlHandlerMapping中的url就是我们实现类的addViewControllers方法中设置的url,然后controller是ParameterizableViewController,他其实就是把我们实现类的addViewControllers方法中设置的view名加入到了ModelandView中了,就这样搞定了。