狂神学习:SpringBoot配置文件

SpringBoot自动装配原理

1. 总结

  1. SpringBoot启动会加载大量的自动装配类
  2. 寻找需要的功能有没有在SpringBoot默认写好的自动装配类中
  3. 查看自动装配类中配置了哪些组件,只要需要用的组件存在其中,就不需要手动配置了
  4. 给容器中自动配置类添加组件时,会从properties类中获取某些属性。只需配置文件中指定这些属性的值的即可。
  5. 可以通过debug=true查看自动配置哪些生效。在这里插入图片描述

xxxxAutoConfiguration自动配置类;给容器中添加组件
xxxxProperties 封装配置文件中相关属性 .yaml

2. MVC自动装配原理

SpringBoot自动配置在Spring默认基础上添加了以下功能

2.1 ContentNegotiatingViewResolver 内容协商视图解析器

   可以支持静态资源文件夹的路径,以及webjar。自动配置了ViewResolver(SpringMVC的视图解析器)。根据方法返回值取得视图对象(View),然后由视图对象决定如何渲染(转发,重定向)。
  1. 找到WebMvcAutoConfiguration类,搜索ContentNegotiatingViewResolver,找到viewResolver方法。ContentNegotiatingViewResolver使用所有其他视图解析器来定位视图,因此它具有较高的优先级
		@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;
		}
  1. 找到ContentNegotiatingViewResolver中resolveViewName方法,此方法用于解析视图
	// 注解说明:@Nullable 参数可为null
	@Override
	@Nullable
	public View resolveViewName(String viewName, Locale locale) throws Exception {
		RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
		Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
		List<MediaType> requestedMediaTypes = getMediaTypes(((ServletRequestAttributes) attrs).getRequest());
		if (requestedMediaTypes != null) {
		// 获取候选的视图对象
			List<View> candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes);
			// 选择一个最合适的视图对象,返回次此对象。
			View bestView = getBestView(candidateViews, requestedMediaTypes, attrs);
			if (bestView != null) {
				return bestView;
			}
		}

		String mediaTypeInfo = logger.isDebugEnabled() && requestedMediaTypes != null ?
				" given " + requestedMediaTypes.toString() : "";

		if (this.useNotAcceptableStatusCode) {
			if (logger.isDebugEnabled()) {
				logger.debug("Using 406 NOT_ACCEPTABLE" + mediaTypeInfo);
			}
			return NOT_ACCEPTABLE_VIEW;
		}
		else {
			logger.debug("View remains unresolved" + mediaTypeInfo);
			return null;
		}
	}
  1. 查看getCandidateViews()方法,把所有的视图解析器拿出来,进行循环,挨个解析。
	private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes)
			throws Exception {

		List<View> candidateViews = new ArrayList<>();
		if (this.viewResolvers != null) {
			Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set");
			for (ViewResolver viewResolver : this.viewResolvers) {
				View view = viewResolver.resolveViewName(viewName, locale);
				if (view != null) {
					candidateViews.add(view);
				}
				for (MediaType requestedMediaType : requestedMediaTypes) {
					List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType);
					for (String extension : extensions) {
						String viewNameWithExtension = viewName + '.' + extension;
						view = viewResolver.resolveViewName(viewNameWithExtension, locale);
						if (view != null) {
							candidateViews.add(view);
						}
					}
				}
			}
		}
		if (!CollectionUtils.isEmpty(this.defaultViews)) {
			candidateViews.addAll(this.defaultViews);
		}
		return candidateViews;
	}

ContentNegotiatingViewResolver 这个视图解析器就是用来组合所有的视图解析器的。

组合逻辑如下

  1. ContentNegotiatingViewResolver类有个属性viewResolvers
	@Nullable
	private List<ViewResolver> viewResolvers;
  1. initServletContext()方法,对属性viewResolvers,进行赋值的。
// beanFactory工具中获取容器中的所有视图解析, ViewRescolver.class 把所有的视图解析器来组合
	@Override
	protected void initServletContext(ServletContext servletContext) {
		Collection<ViewResolver> matchingBeans =
				BeanFactoryUtils.beansOfTypeIncludingAncestors(obtainApplicationContext(), ViewResolver.class).values();
		if (this.viewResolvers == null) {
			this.viewResolvers = new ArrayList<>(matchingBeans.size());
			for (ViewResolver viewResolver : matchingBeans) {
				if (this != viewResolver) {
					this.viewResolvers.add(viewResolver);
				}
			}
		}
		else {
			for (int i = 0; i < this.viewResolvers.size(); i++) {
				ViewResolver vr = this.viewResolvers.get(i);
				if (matchingBeans.contains(vr)) {
					continue;
				}
				String name = vr.getClass().getName() + i;
				obtainApplicationContext().getAutowireCapableBeanFactory().initializeBean(vr, name);
			}

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

给自己容器添加一个视图解析器

  1. 实现ViewResolver接口

2.2 转换器和格式化器

  1. 拿到配置文件中的格式化规则
		@Bean
		@Override
		public FormattingConversionService mvcConversionService() {
			Format format = this.mvcProperties.getFormat();
			WebConversionService conversionService = new WebConversionService(new DateTimeFormatters()
					.dateFormat(format.getDate()).timeFormat(format.getTime()).dateTimeFormat(format.getDateTime()));
			addFormatters(conversionService);
			return conversionService;
		}
  1. WebMvcAutoConfiguration类的getDateFormat()方法
// 日期形式 dd/MM/yyyy
		private String dateTime;
		public String getDateTime() {
			return this.dateTime;
		}

如果配置了自己的格式方式,会注册到Bean中生效,可以在配置文件中配置日期格式化规则

3.修改SpringBoot的默认配置

新建一个config包,新建一个类实现WebMvcConfigurer接口。

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
  // 视图跳转
    @Override
    public void addViewControllers(ViewControllerRegistry registry){
        registry.addViewController("/kuang").setViewName("test");
    }
}

4.总结

  1. WebMvcAutoConfiguration 是 SpringMVC的自动配置类,里面有一个类WebMvcAutoConfigurationAdapter

  2. 这个类上有一个注解,在做其他自动配置时会导入:@Import(EnableWebMvcConfiguration.class)
    在这里插入图片描述

  3. 点进EnableWebMvcConfiguration这个类,它继承了一个父类:DelegatingWebMvcConfiguration
    在这里插入图片描述
    DelegatingWebMvcConfiguration.class 从容器中获取所有的WebMvcConfigurer
    在这里插入图片描述

  4. 以viewController为参考

@Override
	protected void addViewControllers(ViewControllerRegistry registry) {
		this.configurers.addViewControllers(registry);
	}
  1. 进入addViewControllers()方法
    将所有的 WebMvcConfigurer 相关配置一起调用,包括自己配置和Spring配置
	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		for (WebMvcConfigurer delegate : this.delegates) {
			delegate.addViewControllers(registry);
		}
	}

5.全面接管SpringMVC

在配置类中加一个@EnableWebMvc

  1. @EnableWebMvc中
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
  1. DelegatingWebMvcConfiguration.class继承WebMvcConfigurationSupport
    在这里插入图片描述
  2. WebMvc自动配置类引用过WebMvcConfigurationSupport.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 {
    
}

**@EnableWebMvc将WebMvcConfigurationSupport组件导入进来了;

而导入的WebMvcConfigurationSupport只是SpringMVC最基本的功]nmjvv **

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值