SpringBoot项目无需各种配置文件,一个main方法,就能把项目启动起来。那么我们看看SpringBoot是如何进行自动配置和启动的。 SpringBoot通过main方法启动SpringApplication类的静态方法run()来启动项目。 ![](https://img.kancloud.cn/27/b7/27b7acab2376c88a7f2db446ceb1e155_613x236.png) 根据注释的意思,run方法从一个使用了默认配置的指定资源启动一个SpringApplication并返回ApplicationContext对象,这个默认配置如何指定呢? ![](https://img.kancloud.cn/17/01/170135de72ff393f4aa93a68229ccc38_920x251.png) ***** 这个默认配置来源于@SpringBootApplication注解,这个注解是个复合注解,里面还包含了其他注解。 ![](https://img.kancloud.cn/6a/db/6adbc4e0f84194f40841eecd8e7b4338_964x333.png) 其中有三个注解是比较重要的: @SpringBootConfiguration:这个注解的底层是一个@Configuration注解,意思被@Configuration注解修饰的类是一个IOC容器,支持JavaConfig的方式来进行配置; @ComponentScan:该注解的功能开启组件扫描,可以自动扫描指定包路径下的Spring注解。@Controller/@Service/@Component/@Repository等注解加载到IOC容器中; @EnableAutoConfiguration:这个注解表明启动自动装配,里面包含连个比较重要的注解@AutoConfigurationPackage和@Import。 ![](https://img.kancloud.cn/73/42/7342bcaca606738e233d4ca047471aa8_720x254.png) @AutoConfigurationPackage和@ComponentScan一样,也是将主配置类所在的包及其子包里面的组件扫描到IOC容器中,但是区别是@AutoConfigurationPackage扫描@Enitity、@MapperScan等第三方依赖的注解,@ComponentScan只扫描@Controller/@Service/@Component/@Repository这些常见注解。所以这两个注解扫描的对象是不一样的。 @Import(AutoConfigurationImportSelector.class)是自动装配的核心注解,AutoConfigurationImportSelector.class中有个selectImports方法。 ***** 接着我们来看下AutoConfigurationImportSelector这个类的selectImports方法 ![](https://img.kancloud.cn/ee/40/ee400426f64967f4ad60454968a03ccf_976x241.png) selectImports方法还调用了getCandidateConfigurations方法 ![](https://img.kancloud.cn/a6/c3/a6c311d0648c510b524e499d87ed7a5f_937x525.png) getCandidateConfigurations方法中,我们可以看下断言,说找不到**META-INF/spring.factories**,由此可见,这个方法是用来找META-INF/spring.factories文件的 ![](https://img.kancloud.cn/fa/54/fa5467108d23cb91569029bfe9076117_1123x353.png) ![](https://img.kancloud.cn/48/90/4890b24b3cfd3268dcc858deb2140af5_1060x265.png) ![](https://img.kancloud.cn/09/c4/09c41c4ae296cfb3ac12e401702766ed_1210x605.png) 我们可以定位到这个方法所在的类处于spring-boot-autoconfigure-*.jar包中,* ![](https://img.kancloud.cn/c3/2e/c32eb5704392ccd3be6c3400e99a7f72_484x285.png) *其中spring.factories文件是一组组的key=value的形式,包含了key为EnableAutoConfiguration的全类名,value是一个*AutoConfiguration类名的列表,以逗号分隔。 ![](https://img.kancloud.cn/eb/0a/eb0a8749ba75f2fa538781e7d8b497f0_1406x734.png) **最终**,@EnableAutoConfiguration注解通过@SpringBootApplication注解被间接的标记在了SpringBoot的启动类上,SpringApplicaton.run方法的内部就会执行selectImports方法,进而找到所有JavaConfig配置类全限定名对应的class,然后将所有自动配置类加载到IOC容器中。 ***** 那么这些类是如何获取默认属性值的呢?以我们熟悉的**RedisAutoConfiguration**为例,它是springboot集成redis的自动配置类 ![](https://img.kancloud.cn/f5/e0/f5e0011939e4e0dd3fe313b54da98c3a_766x362.png) 该类上开启了@EnableConfigurationProperties({RedisProperties.class})注解,最终找到了RedisProperties类。 ![](https://img.kancloud.cn/53/3a/533a480f862d7b9df6b6b9430a2c1924_768x638.png) 至此,我们大致可以了解。在全局配置的属性如:server.port等,通过@ConfigurationProperties注解,绑定到对应的XxxxProperties配置实体类上封装为一个bean,然后再通过@EnableConfigurationProperties注解导入到Spring容器中。 此处还有一个问题:* 我们有些配置类不需要导入,例如不需要Redis,他会不会给我们导入呢? 答案是:不会 决定配置类是否生效的一个重要因素就是@Conditional注解 只有符合要求才能决定配置类是否生效 **下面附上一个常用条件注解** ~~~text @ConditionalOnBean(上下文中存在某个对象时,才会实例化一个Bean) @ConditionalOnMissingBean(上下文中不存在某个对象时,才会实例化一个Bean) @ConditionalOnClass(某个class位于类路径,才会实例化一个Bean) @ConditionalOnMissingClass(某个class类路径上不存在的时候,才会实例化一个Bean) @ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean) @ConditionalOnNotWebApplication(不是web应用) ~~~ ***** **总结:** 1.SpringBoot启动的时候通过@EnableAutoConfiguration注解找到META-INF/spring.factories文件中的所有自动配置类,并对其加载,这些自动配置类都是以AutoConfiguration结尾来命名的。 2.这些以AutoConfiguration结尾来命名的类实际上就是一个JavaConfig形式的IOC容器配置类,通过以Properties结尾命名的类中取得在全局配置文件中配置的属性,如server.port。 *Properties类的含义:封装配置文件的相关属性。 *AutoConfiguration类的含义:自动配置类,添加到IOC容器中。 推荐阅读:https://www.cnblogs.com/krock/p/15142384.html