本文共 8249 字,大约阅读时间需要 27 分钟。
SpringBoot的核心思想:自动配置
4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.7.RELEASE com.muhan springboot_study01 0.0.1-SNAPSHOT springboot_study01 Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin
我们发现,在springboot的依赖中都是 spring-boot-starter-???
,而这就是springboot的一个个场景启动器。如果我们想要配置web项目,那我们只需要导入springboot的web项目的启动器就可以了,springboot就会帮我们自动装配,就会帮我们配置我们需要的一切
我们从子项目中可以点击进入它的父项目
点进来之后我们可以看到,这个父项目就是springboot的主依赖,在父项目中配置了很多,字符编码,配置文件过滤,各种各样的插件等等,进入父项目,这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;以后我们导入依赖默认是不需要写版本;但是如果导入的包没有在依赖中管理着就需要手动配置版本了。
我们要想加一个包,就要去找这个包的启动器,一般我们都会去官网上去找。如果我们自己添加了一个包的版本和springboot不兼容,那么这个包就不会被spring托管,也就不会产生任何作用。分析这个主程序类,我们发现这个类上有一个注解@SpringBootApplication
,这个注解是用来标注这是一个springboot的主程序类,表明它是一个springboot应用,是创建项目时自己生成的,类中是程序主入口的main方法,方法里面有一个run
方法用来运行springboot
@SpringBootApplication
这个注解,发现这个注解上有很多注解 下面我们一个个的去分析这些注解 其中前四个注解为元注解
@Target({ ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited
@Inherited
元注解是一个标记注解,@Inherited
阐述了某个被标注的类型是被继承的。 如果一个使用了@Inherited
修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。我们点进去这个注解,发现它除了三个元注解就只有一个@Configuration
自定义注解
@Configuration
注解,发现除了三个元注解还有一个@Component
注解 得出结论:有了@Component这个注解,说明这个类就是一个spring的一个组件,或者说是springboot的一个组件,因为有了这个组件所以它才能存在于IOC容器中,才能被spring所管理, 点进去@EnableAutoConfiguration
这个注解,我们发现除了元注解外有两个自定义注解@AutoConfigurationPackage
和@Import(AutoConfigurationImportSelector.class)
(1)@AutoConfigurationPackage——自动导入以及注册包
点进去这个注解,发现它注册了一个注册器Registrar
Registrar
,发现它实现了一个ImportBeanDefinitionRegistrar
接口,实现这个接口让该类成为了拥有注册bean的能力 得出结论:@AutoConfigurationPackage
注解就是一个自动导入以及注册包的注解,是因为它里面的Registrar实现了ImportBeanDefinitionRegistrar
接口 (2)@Import(AutoConfigurationImportSelector.class)——@EnableAutoConfiguration自动导入的核心
先点进去AutoConfigurationImportSelector
中,发现这个类是一个很庞大的类,里面定义了许多自动配置,导包东西。 重点方法:getCandidteConfigurations() 我们在这个类中找到getCandidteConfigurations()
这个方法 protected ListgetCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }
我们发现在getCandidteConfigurations()
这个方法里又调用了SpringFactoriesLoader.loadFactoryNames()
这个方法。
SpringFactoriesLoader
(spring的一个工厂加载器)去loadFactoryNames
(获得它的名字)。里面传入了getSpringFactoriesLoaderFactoryClass(),
参数,(获得这个类的Class),和getBeanClassLoader()
参数(获得它里面的bean,就是所有组件的类加载器) Listconfigurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
然后下面又使用了断言Assert,去断言这个configurations不为空,就去找一个文件META-INF/spring.factories
,如果找不到就需要去这个文件里配置(大概是这个意思)
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct.");getCandidteConfigurations()—>loadFactoryNames()
分析完这些我们点进去loadFactoryNames
这个方法看一下
我们可以发现loadFactoryNames()
中传入的getBeanClassLoader()
类加载器 被传入loadSpringFactories()
方法中了
loadSpringFactories()
方法,首先我们发现这个传入的参数ClassLoader
前面有一个@Nullable
的注解,这个注解的意思就是说该参数可以为空。然后我们分析代码发现如果ClassLoader
不为空它就回去找这个资源FACTORIES_RESOURCE_LOCATION
META-INF/spring.factories 我们点进去这个FACTORIES_RESOURCE_LOCATION
看看到底要找哪个资源,点进去发现,原来如此!如果这个传过来的Classloader
不为空,就回去找META-INF/spring.factories
这个资源。真的是应证了之前的断言。 然后我们去找这个文件看看,在Maven里面的spring-boot-autoconfigure
包下的META-INF/spring.factories
我们再看看这个文件里面有什么 打开之后发现这个文件里面配置了许多许多东西,有初始化的配置,应用程序监听器配置,自动配置导入监听器,自动配置导入过滤器,自动配置,故障分析仪,模板可用性提供者配置…一大堆配置 META-INF/spring.factories—>WebMvcAutoConfiguration 我们在Auto Configure自动配置中找到WebMvcAutoConfiguration
这个配置类(其他类也一样),然后点进去 WebMvcAutoConfiguration—>WebMvcAutoConfigurationAdapter
WebMvcAutoConfiguration
这个类是一个非常庞大的类,我们不去管它,直接去找这个类中WebMvcAutoConfigurationAdapter
这个类,这个类就是WebMvc自动配置的适配器类 我们看见里面有两个注解:@Import(EnableWebMvcConfiguration.class)
和@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
这两个注解的作用是
WebMvcProperties
WebMvcAutoConfigurationAdapter–>WebMvcProperties(类上注解的参数) 然后我们点进去WebMvcProperties
看一下都是什么,点进去发现它有一个前缀spring.mvc
,而且它可以配置很多东西,比如格式化,国际化,日期格式等等…一些配置 WebMvcProperties
这个类,发现这个类是为了让我们去自己去配置一些东西的。那么我们分析一下,得出结论:每一个*****AutoConfiguration
都对应一个****Properties
配置 那么我们应该怎么去自己配置呢?
我们发现项目的resources目录下有一个application.properties文件(项目自动生成的),这个配置文件就是用来自定义配置的 根据刚才我们分析的源码,我们发现可以使用spring.mvc为前缀去配置一些东西(这里面的配置就是对应刚才我们找到的WebMvcProperties
中的一些可以配置的东西)。假如我们再这里配置了,那么springboot的默认配置就会失效 当然我们还可以新建一个application.yml,并使用yml的风格去配置
分析WebMvcAutoConfigurationAdapter
然后我们分析WebMvcAutoConfigurationAdapter
这个类,发现它配置了视图解析器 还配置了国际化资源,就是点击切换中英文功能 还有消息代码解析器,主要是用来处理乱码的 还配置了一些格式化的资源,比如时间日期就要用到这个对象,需要手动去配置 WebMvcAutoConfiguration—>WebMvcAutoConfigurationAdapter—>addResourceHandlers(重点方法) 然后!重点来了:还配置了资源处理器,addResourceHandlers
方法可以让我们自己去添加自己想要的资源。我们分析代码发现,如果我们想要导入一个外部资源就要去遵循addResourceHandlers
方法里面的规则。
@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) { if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); return; } Duration cachePeriod = this.resourceProperties.getCache().getPeriod(); CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl(); //如果/webjars/**下面已经有资源了就去classpath:/META-INF/resources/webjars/下去找 if (!registry.hasMappingForPattern("/webjars/**")) { customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**") .addResourceLocations("classpath:/META-INF/resources/webjars/") .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); } //如过没有的话,就会去staticPathPattern下去找,staticPathPattern实质就是"/**",也就是/webjars/**下面说没有的话就去/**下去找 String staticPathPattern = this.mvcProperties.getStaticPathPattern(); if (!registry.hasMappingForPattern(staticPathPattern)) { customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern) .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())) .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); }}
我们还发现一个问题,在springboot项目中并没有之前我们使用ssm框架时的webapp
目录,那么我们的外部资源应该放在哪里呢?
/webjars/**
目录下面所有的资源,我们再之后的springboot的学习中会用到。 导入资源的第一种方式:使用webjars
的导入一个jquery
资源
staticPathPattern
我们再点进去看一下,发现它给staticPathPattern
赋值为"/**"
,也就是说静态资源放在根目录下也是可以的 分析完这个我们返回去继续分析WebMvcAutoConfigurationAdapter这个类 WebMvcAutoConfiguration—>WebMvcAutoConfigurationAdapter–>FaviconConfiguration(图标)
发现一个好玩的东西:可以设置网站的图标spring.mvc.favicon.enabled
,可以用过这个组件去自定义网站的图标,但是图标名必须是**/favicon.ico
,路径是根目录下的哪个位置,比如说resources目录下放一个名为favicon.ico
的图标就可以将原有的小叶子替换掉 转载地址:http://stiwi.baihongyu.com/