SpringBoot自动装配原理
1. 总结
- SpringBoot启动会加载大量的自动装配类
- 寻找需要的功能有没有在SpringBoot默认写好的自动装配类中
- 查看自动装配类中配置了哪些组件,只要需要用的组件存在其中,就不需要手动配置了
- 给容器中自动配置类添加组件时,会从properties类中获取某些属性。只需配置文件中指定这些属性的值的即可。
- 可以通过
debug=true
查看自动配置哪些生效。
xxxxAutoConfiguration自动配置类;给容器中添加组件
xxxxProperties 封装配置文件中相关属性 .yaml
2. MVC自动装配原理
SpringBoot自动配置在Spring默认基础上添加了以下功能
2.1 ContentNegotiatingViewResolver 内容协商视图解析器
可以支持静态资源文件夹的路径,以及webjar。自动配置了ViewResolver(SpringMVC的视图解析器)。根据方法返回值取得视图对象(View),然后由视图对象决定如何渲染(转发,重定向)。
- 找到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;
}
- 找到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;
}
}
- 查看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 这个视图解析器就是用来组合所有的视图解析器的。
组合逻辑如下
- ContentNegotiatingViewResolver类有个属性viewResolvers
@Nullable
private List<ViewResolver> viewResolvers;
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);
}
给自己容器添加一个视图解析器
- 实现ViewResolver接口
2.2 转换器和格式化器
- 拿到配置文件中的格式化规则
@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;
}
- 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.总结
-
WebMvcAutoConfiguration 是 SpringMVC的自动配置类,里面有一个类WebMvcAutoConfigurationAdapter
-
这个类上有一个注解,在做其他自动配置时会导入:@Import(EnableWebMvcConfiguration.class)
-
点进EnableWebMvcConfiguration这个类,它继承了一个父类:DelegatingWebMvcConfiguration
DelegatingWebMvcConfiguration.class 从容器中获取所有的WebMvcConfigurer
-
以viewController为参考
@Override
protected void addViewControllers(ViewControllerRegistry registry) {
this.configurers.addViewControllers(registry);
}
- 进入addViewControllers()方法
将所有的 WebMvcConfigurer 相关配置一起调用,包括自己配置和Spring配置
@Override
public void addViewControllers(ViewControllerRegistry registry) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.addViewControllers(registry);
}
}
5.全面接管SpringMVC
在配置类中加一个@EnableWebMvc
- @EnableWebMvc中
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
- DelegatingWebMvcConfiguration.class继承WebMvcConfigurationSupport
- 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 **