32.SpringBoot学习笔记

扩展与全面接管SpringMVC

Posted by Chen Xingxu on June 20, 2020

32.SpringBoot学习笔记–扩展与全面接管SpringMVC

扩展 SpringMVC

原来使用 SpringMVC 配置方法:

<mvc:view-controller path="/hello" view-name="success"/>
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/hello"/>
        <bean></bean>
    </mvc:interceptor>
</mvc:interceptors>
<mvc:default-servlet-handler/>

Spring Boot 的配置方法:

If you want to keep those Spring Boot MVC customizations and make more MVC customizations (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc.

参考:Spring MVC Auto-configuration

示例

既保留了 Spring Boot 的所有自动配置,也能用扩展的配置。

demo.yangxu.springboot.config.MyMvcConfig

package demo.yangxu.springboot.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


//使用WebMvcConfigurer扩展SpringMVC的功能
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //浏览器发送 /yangxu 请求来到 success
        registry.addViewController("/yangxu").setViewName("success");
    }
}

访问 http://localhost:8080/yangxu 即跳转到 success

参考

org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter

WebMvcAutoConfiguration 是 SpringMVC 的自动配置类,在做其他自动配置时会导入 @Import(EnableWebMvcConfiguration.class)

// Defined as a nested config to ensure WebMvcConfigurer is not read when not
// on the classpath
@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {}

org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.EnableWebMvcConfiguration

@Configuration(proxyBeanMethods = false)
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {}

org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration#configurers

private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();

org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration#setConfigurers

从容器中获取所有的 WebMvcConfigurer

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

参考实现:

org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration#addViewControllers

@Override
protected void addViewControllers(ViewControllerRegistry registry) {
    this.configurers.addViewControllers(registry);
}

org.springframework.web.servlet.config.annotation.WebMvcConfigurerComposite#addViewControllers

将所有的 WebMvcConfigurer 相关配置一起调用,容器中所有的 WebMvcConfigurer 都会一起起作用。

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    for (WebMvcConfigurer delegate : this.delegates) {
        delegate.addViewControllers(registry);
    }
}

自己写的配置类也会被调用。

效果:SpringMVC的自动配置和自己写的扩展配置都会起作用。

全面接管 SpringMVC

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc, or alternatively add your own @Configuration-annotated DelegatingWebMvcConfiguration as described in the Javadoc of @EnableWebMvc.

Spring Boot 对 SpringMVC 的自动配置都失效了,全都需要自己配置。在配置类中添加 @EnableWebMvc 即可。

参考:Spring MVC Auto-configuration

示例

demo.yangxu.springboot.config.MyMvcConfig

package demo.yangxu.springboot.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


//使用WebMvcConfigurer扩展SpringMVC的功能
@EnableWebMvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //浏览器发送 /yangxu 请求来到 success
        registry.addViewController("/yangxu").setViewName("success");
    }
}

@EnableWebMvc 自动配置失效参考原理

org.springframework.web.servlet.config.annotation.EnableWebMvc

@EnableWebMvc 的核心,导入了 DelegatingWebMvcConfiguration 组件,DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport。

@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration

@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {}

org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
		ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {}

@ConditionalOnMissingBean(WebMvcConfigurationSupport.class):容器中没有 WebMvcConfigurationSupport 组件的时候,这个自动配置类才生效。

@EnableWebMvc 导入了 DelegatingWebMvcConfiguration 组件,而 DelegatingWebMvcConfiguration 继承于 WebMvcConfigurationSupport,DelegatingWebMvcConfiguration 实际上是 WebMvcConfigurationSupport 的一种,所以 WebMvcAutoConfiguration 自动配置类失效。

导入的 WebMvcConfigurationSupport 组件只是 SpringMVC 的基本功能。

修改 Spring Boot 的默认配置

模式:

1、Spring Boot 在自动配置组件时,先看容器中有没有用户自己配置的(@Bean、@Component),如果有就使用用户配置的,如果没有,就自动配置。如果有些组件可以有多个(如:ViewResolver),将用户配置的和默认的组合起来;

2、在 Spring Boot 中有很多的 xxxConfigurer 进行扩展配置;

3、在 Spring Boot 中有很多的 xxxCustomizer 进行定制配置。