SpringBoot——web开发之SpringMVC自动配置原理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/rubulai/article/details/82715134

一、SpringBoot为SpringMVC提供的自动配置

1、SpringMVC的自动配置可参考官方文档:Spring Web MVC Framework

2、SpringBoot为SpringMVC提供的自动配置:参考类WebMvcAutoConfiguration

①Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans

    SpringBoot为SpringMVC自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象——View,视图对象决定如何渲染,是转发还是重定向),SpringBoot通过ContentNegotiatingViewResolver组合所有的视图解析器(遍历容器中所有的视图解析器,并将这些视图解析器添加到viewResolvers中):

protected void initServletContext(ServletContext servletContext) {
	Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), ViewResolver.class).values();
	ViewResolver viewResolver;
	if (this.viewResolvers == null) {
		this.viewResolvers = new ArrayList(matchingBeans.size());
		Iterator var3 = matchingBeans.iterator();

		while(var3.hasNext()) {
			viewResolver = (ViewResolver)var3.next();
			if (this != viewResolver) {
				this.viewResolvers.add(viewResolver);
			}
		}
	} else {
		for(int i = 0; i < this.viewResolvers.size(); ++i) {
			viewResolver = (ViewResolver)this.viewResolvers.get(i);
			if (!matchingBeans.contains(viewResolver)) {
				String name = viewResolver.getClass().getName() + i;
				this.obtainApplicationContext().getAutowireCapableBeanFactory().initializeBean(viewResolver, name);
			}
		}
	}

	if (this.viewResolvers.isEmpty()) {
		this.logger.warn("Did not find any ViewResolvers to delegate to; please configure them using the 'viewResolvers' property on the ContentNegotiatingViewResolver");
	}

	AnnotationAwareOrderComparator.sort(this.viewResolvers);
	this.cnmFactoryBean.setServletContext(servletContext);
}

我们可以自己定制视图解析器,并将自定义的视图解析器添加到容器中:ContentNegotiatingViewResolver会自动的将其组合进来,例如:这里定义了一个静态内部类,使其实现ViewResolver接口

@SpringBootApplication
public class SpringBootWebApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootWebApplication.class, args);
    }

    @Bean
    public ViewResolver myViewResolver(){
        return new MyViewResolver();
    }

    public static class MyViewResolver implements ViewResolver{

        @Override
        public View resolveViewName(String s, Locale locale) throws Exception {
            return null;
        }
    }
}

②Support for serving static resources, including support for WebJars (see below):SpringBoot支持静态资源文件夹路径,包括webjars

③Static index.html support:SpringBoot提供了静态首页访问

④Custom Favicon support (see below):自定义的 favicon.ico

⑤自动注册了Converter , GenericConverter , Formatter beans等转换器(转换器:页面传给后台的值都是文本类型的,后台拿到这些数据封装对象的时候可能需要进行类型转换,比如将"true"转换为Boolean类型,将“18”转为Integer类型等)和格式化器

@Bean
@ConditionalOnProperty(prefix = "spring.mvc", name = "date‐format")//在文件中配置日期格式化的规则
public Formatter<Date> dateFormatter() {
	return new DateFormatter(this.mvcProperties.getDateFormat());//日期格式化组件
}

我们也可以自定义格式化器,方式类似于自定义视图解析器

⑥Support for HttpMessageConverters (see below):HTTP消息转换器,比如报文是对象还是JSON格式,也可以自定义

⑦Automatic registration of MessageCodesResolver (see below):定义错误代码生成规则

⑧Automatic use of a ConfigurableWebBindingInitializer bean (see below):自动将请求数据转化为JavaBean,可自定义

SpringBoot为SpringMVC做的所有自动配置都在org.springframework.boot.autoconfigure.web下

另外:

If you want to keep Spring Boot MVC features, and you just want to add additional MVC configuration(interceptors, formatters, view controllers etc.)you can add your own @Configuration class of type WebMvcConfigurerAdapter,but without @EnableWebMvc . If you wish to provide custom instances of RequestMappingHandlerMapping , RequestMappingHandlerAdapter or ExceptionHandlerExceptionResolver you can declare a WebMvcRegistrationsAdapter instance providing such components.If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

二、如何修改SpringBoot的默认配置

模式:

1、SpringBoot在自动配置很多组件的时候,会先看容器中有没有用户自己配置的(@Bean、@Component)对应组件,如
果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(比如ViewResolver)SpringBoot会将用户配置的和默
认的组合起来:通过注解@ConditionalOnMissingBean来判断用户有没有自定义组件

@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
	return new OrderedHiddenHttpMethodFilter();
}

2、在SpringBoot中会有非常多的XxxConfigurer帮助我们进行扩展配置

3、在SpringBoot中会有很多的XxxCustomizer帮助我们进行定制配置

三、扩展SpringMVC

    比如:配置某些请求的视图或者某些请求的拦截器,在之前我们可以这么配置

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

现在我们可以自定义一个配置类:使用@Configuration标注,是WebMvcConfigurerAdapter类型,不能标注@EnableWebMvc,然后重写相应的方法即可,这样我们既保留了SpringBoot中所有的自动配置,也启用了我们扩展的配置

//通过重写WebMvcConfigurerAdapter的相应方法来扩展SpringMVC
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //对于一些简单的请求,比如不需要从后台获取数据的请求,可以采用这种方式直接返回页面,而不需要在Controller中写一些空方法
        registry.addViewController("/bdm").setViewName("success");
    }
}

扩展原理:

在做其他自动配置时会导入EnableWebMvcConfiguration:@Import(EnableWebMvcConfiguration.class)

@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
    ...
}

在该类中会将所有的WebMvcConfigurer组合起来:使容器中所有的WebMvcConfigurer一起起作用

//从容器中获取所有的WebMvcConfigurer
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
	if (!CollectionUtils.isEmpty(configurers)) {
		this.configurers.addWebMvcConfigurers(configurers);
	}
}
//一个参考实现;将所有的WebMvcConfigurer相关配置都来一起调用;
@Override
public void addViewControllers(ViewControllerRegistry registry) {
	...
	for (WebMvcConfigurer delegate : this.delegates) {
		delegate.addViewControllers(registry);
	}
	...
}

四、全盘接管SpringgMVC

当我们不需要使用SpringBoot为SpringMVC提供的所有自动配置的时候,可以全面接管SpringMVC(不推荐这样做),只需要在配置类中添加@EnableWebMvc即可:

//通过重写WebMvcConfigurerAdapter的相应方法来扩展SpringMVC
@EnableWebMvc
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //对于一些简单的请求,比如不需要从后台获取数据的请求,可以采用这种方式直接返回页面,而不需要在Controller中写一些空方法
        registry.addViewController("/bdm").setViewName("success");
    }
}

原理:

SpringBoot中为SpringMVC提供的自动配置生效的前提是容器中不存在WebMvcConfigurationSupport:

@Configuration
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
   ...
}

一旦容器中存在了WebMvcConfigurationSupport,则WebMvcAutoConfiguration组件不会被加载到容器中,而@EnableWebMvc会@Import({DelegatingWebMvcConfiguration.class}),DelegatingWebMvcConfiguration继承自WebMvcConfigurationSupport,因此会导致WebMvcAutoConfiguration失效

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

WebMvcConfigurationSupport中只实现了SpringMVC最基本的功能,所以不推荐全面接管SpringMVC,除非项目中很少使用web模块

猜你喜欢

转载自blog.csdn.net/rubulai/article/details/82715134