SpringBoot(3)-MVC自动配置及自定义视图控制器

1. 主要类:

WebMvcAutoConfiguration: MVC的自动配置类
EnableWebMvcConfiguration: 启用WebMvcConfiguration的类
DelegatingWebMvcConfiguration: WebMvcConfiguration委托的代理类
WebMvcConfigurerComposite: “具体WebMvcConfiguration的委托类”
`
WebMvcAutoConfigurationAdapter: MVC自动配置适配器,其实现了WebMvcConfiguration
WebMvcConfigurer: MVC配置接口
WebMvcConfigurerAdapter: MVC配置适配器(1.8后弃用,因为接口支持default默认实现)

2. 视图解析器初始化:

 springboot启动后会自动配置mvc的组件,即WebMvcAutoConfiguration,自动进行mvc的一些配置
 其内部静态类WebMvcAutoConfigurationAdapter也是一个组件,通过@Import导入EnableWebMvcConfiguration组件

	@Configuration(proxyBeanMethods = false)
	@Import(EnableWebMvcConfiguration.class)
	@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
	@Order(0)
	public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {

 EnableWebMvcConfiguration继承了DelegatingWebMvcConfiguration委托代理类

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

 代理类通过setConfigurers方法来初始化mvc配置的具体委托类
 @Autowired会从容器总把实现WebMvcConfigurer接口的类都注入到configurers
 然后将所有的mvc配置类添加到WebMvcConfigurerComposite

@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);
		}
	}
//也实现了WebMvcConfigurer当并没有@Configuration到容器中
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);
		}
	}

 dubug可以知道,默认使用WebMvcAutoConfigurationAdapter

在这里插入图片描述
所以,要想自定义mvc的配置,只需要实现WebMvcConfigurer接口,并将该类放入容器中即可

@Configuration
public class MyConfigure implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/testView").setViewName("success");
    }
}

在这里插入图片描述

3. MVC视图功能配置:

 由上可知,mvc的配置,默认使用WebMvcAutoConfigurationAdapter来配置
 这个类在配置的时候,会往容器中添加三个视图bean,主要关注ContentNegotiatingViewResolver

 注意其该配置resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);设置最高级的Order,后续会提到

	@Configuration(proxyBeanMethods = false)
	@Import(EnableWebMvcConfiguration.class)
	@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
	@Order(0)
	public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {

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

		@Bean
		@ConditionalOnBean(View.class)
		@ConditionalOnMissingBean
		public BeanNameViewResolver beanNameViewResolver() {
			BeanNameViewResolver resolver = new BeanNameViewResolver();
			resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
			return resolver;
		}

		@Bean
		@ConditionalOnBean(ViewResolver.class)
		@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
		public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
			ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
			resolver.setContentNegotiationManager(beanFactory.getBean(ContentNegotiationManager.class));
			// ContentNegotiatingViewResolver uses all the other view resolvers to locate
			// a view so it should have a high precedence
			resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
			return resolver;
		}
		... ... ...

 ContentNegotiatingViewResolver这个视图解析器主要是用来组合所有视图解析器的
 在其内部实现方法initServletContext可以看到,将所有视图解析器(除本类)添加到本类的中viewResolvers

在这里插入图片描述

 可见,想要自定义视图解析器,可以实现ViewResolver接口,然后加入容器即可,本文不论述

4. MVC解析视图过程:

 前端控制器(DispatcherServlet),在第一次调用视图解析器之前,会通过initViewResolvers方法先初始化视图解析器
 该方法中,获取容器内所有视图解析器,即容器中实现ViewResolver接口的类
 然后所有视图解析器根据Order排序,上文提及ContentNegotiatingViewResolver设置了最高级别Order,所以它会排在第一个

在这里插入图片描述

 当初始化视图解析器后,前端控制器通过resolveViewName方法遍历所有视图解析器来解析,能解析立即返回View
 ContentNegotiatingViewResolver排在第一个,所以会最先调用

在这里插入图片描述
 其内部方法通过getCandidateViews来解析出所有视图,最后处理返回一个bestView给前端控制器
在这里插入图片描述

 在getCandidateViews方法中,this.viewResolvers就是之前ContentNegotiatingViewResolver组合的所有视图解析器
 调用各视图解析器的实现方法resolveViewName来解析视图
 有兴趣的可以研究一些这个方法,我就算了

在这里插入图片描述

 详细的MVC执行过程可参考:SpringBoot(2)-MVC执行过程

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页