其他分享
首页 > 其他分享> > Springboot MVC 自动配置

Springboot MVC 自动配置

作者:互联网

Springboot MVC 自动配置

官方文档阅读

https://docs.spring.io/spring-boot/docs/current/reference/html/web.html#web.servlet.spring-mvc.auto-configuration

Spring Boot provides auto-configuration for Spring MVC that works well with most applications.

The auto-configuration adds the following features on top of Spring’s defaults:

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 Boot MVC 定制并进行更多的 MVC 定制(拦截器、格式化程序、视图控制器和其他特性) ,可以添加您自己的 webmvcrer 类型的@Configuration 类,但不要添加@EnableWebMvc。

If you want to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, and still keep the Spring Boot MVC customizations, you can declare a bean of type WebMvcRegistrations and use it to provide custom instances of those components.

如果你想提供自定义的 requestmappinghandler mapping、 requestmappinghandler adapter 或 exceptionhandlerexceptionmvc 定制,你可以声明一个类型为 WebMvcRegistrations 的 bean,并使用它来提供这些组件的自定义实例

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 MVC,你可以添加你自己的@Configuration 注释@EnableWebMvc,或者像在@EnableWebMvc 的 Javadoc 中描述的那样添加你自己的@Configuration 注释 delegatingwebmvcvc 配置。

个人解读

​ SpringBoot本身是为Spring MVC提供了自动配置,一般情况下是满足使用需求的。最近在学习的时候,需要使用矩阵变量,需要对springmvc的配置需要进行更改,遇到了一些疑问,通过源码探索了一下,今天在此总结,方便以后自己来看。

​ 上面的官方文档中,最重要的两段话:

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 Boot MVC 定制并进行更多的 MVC 定制(拦截器、格式化程序、视图控制器和其他特性) ,可以添加您自己的 WebMvcConfigurer类型的@Configuration 类但不要添加@EnableWebMvc

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 MVC,你可以添加你自己的@Configuration 注释@EnableWebMvc,或者添加自己的@Configuration-annotated DelegatingWebMvcConfiguration中的Javadoc中所述@EnableWebMvc

总结一下:如果我们需要定制适合当前开发需求的springmvc,那么有两种方法:

深入理解

首先我们得知道:(推荐使用在自动配置的基础上进行更多定制,即同时使用自动配置以及用户自定义配置

SpringBoot会默认自动配置组件,在自动配置组件的时候,首先会查看IOC容器中是否有用户自定义配置的(即,在@Configuration配置类中,用户使用@Bean添加进容器中的组件),如果有就用用户配置的,如果没有就用自动配置的;如果有些组件可以存在多个,比如我们的视图解析器,就将用户配置的和自己默认的组合起来。

示例代码

这里是推荐方法的使用,至于全面接管的使用,后面再更新吧(如果你看到了这句话,那还没有更新.........)

@Configuration
public class MyConfig implements WebMvcConfigurer {
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        // 移除url中分号:设置为false,不移除;这样,才能从url中取出矩阵变量的值
        urlPathHelper.setRemoveSemicolonContent(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }
}
@Configuration
public class WebConfig /*implements WebMvcConfigurer*/ {

    // WebMvcConfigurer定制化SpringMVC的功能
    @Bean
    public WebMvcConfigurer webMvcConfigurer(){
            @Override
            public void configurePathMatch(PathMatchConfigurer configurer) {
                UrlPathHelper urlPathHelper = new UrlPathHelper();
                // 不移除;后面的内容。矩阵变量功能就可以生效
                urlPathHelper.setRemoveSemicolonContent(false);
                configurer.setUrlPathHelper(urlPathHelper);
            }
}

自动配置原理(推荐方法)

WebMvcConfigurer

  1. 我们知道springboot是自动配置类是WebMvcAutoConfiguration.class

    @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 {
        ......
    }
    
  2. WebMvcAutoConfiguration.class中有一个静态类WebMvcAutoConfigurationAdapter实现了WebMvcConfigurer

    	@Configuration(proxyBeanMethods = false)
    	@Import(EnableWebMvcConfiguration.class)
    	@EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class })
    	@Order(0)
    	public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {...}
    
  3. WebMvcAutoConfigurationAdapter类是实现了WebMvcConfigurer接口,WebMvcConfigurer中提供了许多默认实现的方法,我们正是通过对这些方法的重写,来达到定制的目的。

    public interface WebMvcConfigurer {
        
    	default void configurePathMatch(PathMatchConfigurer configurer) {
    	}
        .......
    }
    
  4. 从注解@Import(EnableWebMvcConfiguration.class)看到,WebMvcAutoConfiguration导入了一个配置等效于@EnableWebMvc的配置类,这个类继承了DelegatingWebMvcConfiguration,而DelegatingWebMvcConfiguration继承了WebMvcConfigurationSupport

    DelegatingWebMvcConfiguration这个类的作用:其实是调用WebMvcConfigurerComposite这个类中的方法,目的是同时加载自动配置和用户自定义的配置

    /**
     * A subclass of {@code WebMvcConfigurationSupport} that detects and delegates
     * to all beans of type {@link WebMvcConfigurer} allowing them to customize the
     * configuration provided by {@code WebMvcConfigurationSupport}. This is the
     * class actually imported by {@link EnableWebMvc @EnableWebMvc}.
     *
     * @author Rossen Stoyanchev
     * @since 3.1
     *WebMvcConfigurationSupport的子类,它检测并委托给WebMvcConfigurer类型的所有bean,允许它们自定义WebMvcConfigurationSupport提供的配置。 这是由@EnableWebMvc实际导入的@EnableWebMvc
     */
    @Configuration(proxyBeanMethods = false)
    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);
    		}
    	}
        
       ........
    }
    

    我们随机选择这个类中任意一个方法,并进入到调用的对应WebMvcConfigurerComposite类中的方法,可以发现:

    这个类的方法,将实现所有WebMvcConfigurer的相关配置bean,包括我们自己配置的和SpringBoot给我们自动配置的,即这里完成了在自动配置的基础上增加我们自定义的配置。下面给出两个示例方法:

    	@Autowired(required = false)
    	public void setConfigurers(List<WebMvcConfigurer> configurers) {
    		if (!CollectionUtils.isEmpty(configurers)) {
                // 从容器中获取所有自定义配置bean
    			this.configurers.addWebMvcConfigurers(configurers);
    		}
    	}
    
    	@Override
    	protected void configurePathMatch(PathMatchConfigurer configurer) {
            // 遍历容器中中相关配置并调用
    		this.configurers.configurePathMatch(configurer);
    	}
    

    查看configurePathMatch()方法:

    将各种自定义配置bean(即WebMvcConfigurer对象)添加到delegates中,并将所有的WebMvcConfigurer相关配置使用对应的方法进行遍历调用(包括springboot自动配置的和我们用户自定义配置的)。

    class WebMvcConfigurerComposite implements WebMvcConfigurer {
    
    	private final List<WebMvcConfigurer> delegates = new ArrayList<>();
    
    	public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) {
    		if (!CollectionUtils.isEmpty(configurers)) {
    			this.delegates.addAll(configurers);
    		}
    	}
    
    	@Override
    	public void configurePathMatch(PathMatchConfigurer configurer) {
            // 遍历调用实现,实现默认的配置以及自定义的配置
    		for (WebMvcConfigurer delegate : this.delegates) {
    			delegate.configurePathMatch(configurer);
    		}
    	}
        ....
    }
    

总结1

所有的WebMvcConfiguration都会被调用,包括springboot自动配置的内容以及我们自己定义的配置。

为什么不能使用@EnableWebMvc(完全控制Spring MVC)

完全控制Spring MVC:SpringBoot对SpringMVC的自动配置失效,所有配置都需要用户自己去配置。

前面提到,如果使用第一种方法的话,就不能使用@EnableWebMvc注解,从WebMvcConfigurer的实现类WebMvcAutoConfigurationAdapter所在的springboot自动配置类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这个组件时,才能使用SpringBoot的自动配置。所以,当我们使用第一种自动配置+自定义配置时,不能使用@EnableWebMvc注解的原因就在此。(从自动配置类WebMvcAutoConfiguration直观分析)

进一步理解,加入@EnableWebMvc注解后SpringMVC的所有自动配置失效的原理:

  1. 查看@EnableWebMvc注解的定义:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
  1. 这个要导入DelegatingWebMvcConfiguration组件:
@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {...}

可以看到DelegatingWebMvcConfiguration是继承WebMvcConfigurationSupport,也就是说如果使用注解@EnableWebMvc,就会向容器添加组件DelegatingWebMvcConfiguration,等同于导入了WebMvcConfigurationSupport,这与springboot自动配置类使用的条件冲突,导致自动配置失效。

总结2

@EnableWebMvc将WebMvcConfigurationSupport组件导入进容器中来了,会导致自动配置失效。

标签:Springboot,配置,MVC,自动,WebMvcConfigurer,Configuration,class,EnableWebMvc
来源: https://www.cnblogs.com/wenhaozou/p/15714755.html