🏆 作者简介:hh_hua,从0到1。
🏆《头衔》:CDSN优秀文章收藏者、CSDN从不评论者
🏆《近期荣誉》:妈妈说我是个好孩子
🏆《博客内容》:从nothing到everything
🏆🎉欢迎 👍点赞✍评论⭐收藏
文章目录
🚀前置知识
🔎相关注解
🦋@ComponentScan
@ComponentScan:用于批量注册bean,该注解会让spring去扫描某些包及其子包中所有的类,然后将满足一定条件的类作为bean注册到spring容器容器中。(详见:@ComponentScan详解)
🦋@Configuration
@Configuration:声明一个类为配置类,目的取代bean.xml配置文件注册bean对象。常与@Bean、@Scope、@Lazy
搭配使用。(详解:@Configuration详解)
配置类是什么?
使用注解和编程方式来代替传统的XML配置文件进行Spring框架配置的一种类,通过@Configuration
来声明该类与普通类的区别,本质而言一种特殊的类。
为何存在配置类?
一切的目的都是为了简化开发,通过自动化的方式来提高生产效率,解放我们的双手。
🦋@Import
@Import:提供了一种显示地从其他地方加载配置类的方式,往往是从第三方导入配置类。(详解:@Import详解)
三种导入方式
- 普通类(相对于下面两种方式)
- 接口ImportSelector的实现类
- 接口ImportBeanDefinitionRegisrtar的实现类
自动配置中使用了第二种方式
🔎SpringBoot启动过程
SpringBoot启动相当复杂,我们只谈重点,以简化之。
简版代码
SpringBoot启动流程的简化版代码:
public static void run(class<?> primaryClass) {
//1.创建一个ApplicationContext实例,即我们常说的IoC容器
ApplicationContext context = createApplicationContext();
//2.将主类(primaryClass)注册到IoC容器中〔简单但重要的第一步)
loadSourceclass(context, primaryclass);
//3.递归加载并处理所有的配置类
processConfigurationClasses(context)
/4.实例化所有的单例Bean(Singleton Bean)
instantiateSingletonBeans(context)
//5.如果是web应用,则启动web服务器(例如Tomcat)
startWebServer(context);
对应示图
详细讲讲重点步骤:加载并处理所有的配置类
加载并处理所有的配置类processConfigurationClasses(..)
public static void processConfigurationClasses(ApplicationContext context) {
//1.1首先从IoC容器中取出当前存在的源配置类
class<?> sourceConfigurationclass = getSourceConfigurationClass(context);
//2.创建一个配置类解析器,然后递归加载并处理应用中所有的配置类
ConfigClassParser parser = new ConfigClassParser(context);parser.parse(sourceConfigurationClass);
//3.1 向IoC容器中注册@Bean方法对应的BeanDefinition
loadBeanDefinitionsFromBeanNethods(parser.configurationClasses);
//3.2向IoC容器中注册ImportBeanDefinitionRegistrar导入的BeanDefinition
loadBeanDefinitionsFromRegistrars(parser.configurationClasses);
🚀什么是SpringBoot自动配置?
定义:SpringBoot 能够根据类路径中的jar依赖、定义的bean以及各种属性设置,自动配置应用的过程,从而使开发人员不在需要定义样板化的配置,按照约定进行编程。
自动配置与自动装配的区别:
自动配置:Auto-Configuration,定义如上。
自动装配:Autowire是注解,用于依赖注入。
🚀SpringBoot是如何自动配置?
先放一张总图:
1.从主启动类的核心注解开始@SpringBootApplication
2.点进@SpringBootApplication
,发现三个核心注解@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan
。
3.先给结论:**@ComponentScan
用于扫描指定的package,找到其中符合条件的类**。
@ComponentScan
是用来扫描包,但是具体实现需要配合@EnableAutoConfiguration
具体实现:
根据@EnableAutoConfiguration
注解中的@EnableAutoConfiguration
注解。
@EnableAutoConfiguration
注解中有@Import({AutoConfigurationPackages.Registrar.class})
一个注册器Registrar,通过这个注册器我们就可以找到当前类所在的包。
4.先给结论:@SpringBootConfiguration
注解本质一个配置类,用于注册到Ioc容器中
5.先给结论:重中之重的注解@EnableAutoConfiguration
用于读取到所有Jar包中的配置文件 META-IF/spring.factories 。
具体实现:
@EnableAutoConfiguration
注解中有@Import({AutoConfigurationImportSelector.class})
,自动配置导入选择器,即自动地、有选择地导入配置。
具体又是如何实现的呢?AutoConfigurationImportSelector
实现了selectImports()
方法,而这其中getAutoConfigurationEntry()
方法。
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
//1.获取 annotationNetadata 的注解@EnableAutoConfiguration 的属性
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
//2.从资源文件 spring.factories中获取EnableAutoConfiguration对应的所有的类
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
//3.通过在注解_@EnableAutoConfiguration 设置exclude 的相关属性,可以排除指定的自动配置类
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
//4.根据注解@Conditional来判断是否需要排除某些自动配置类
configurations = this.getConfigurationClassFilter().filter(configurations);
//5.触发AutoConfiguration导入的相关事件
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
}
而这个getCandidateConfigurations方法的返回值是String,是真正帮我们去读到spring.factories配置文件 。
梳理:
1.通过@EnableAutoConfguration 里面的@AutoConfigurationPackage 注解,将主配置类的所在包皮下面所有子包里面的所有组件扫描加载到 Spring 容器中;
2.同时通过@EnableAutoConfguration 里面的 AutoConfigurationImportSelector 选择器中的 SringFactoriesLoader.loadFactoryNames()方法,获取类路径下的 META-INF/spring.factories 中的资源并经过一些列判断之后作为自动配置类生效到容器中,
3.自动配置类生效后帮我们进行自动配置工作,就会给容器中添加各种组件。
🚀SpringBoot如何修改配置?
虽然SpringBoot帮我们实现了自动配置,但是我们往往需要修改其默认值。对于每一个自动配置类(XXXAutoConfiguration),都对应着一个属性配置类(XXXAutoConfiguration)。前者实例化组件,后者在实例化组件过程中给某些属性赋值,而我们需要赋值的话,则需要通过修改application.xxx
文件的方式。
例如:
//修改服务器端口号
server.port=8085
//修改日期格式
spring.mvc.format.date=yyyy-MM-dd
🚀总结
- SpringBoot启动会加载大量的自动配置类。
- 我们需要的功能有没有在SpringBoot默认写好的自动配置类当中,再来看这个自动配置类中到底配置了哪些组件,只要我们要用的组件在其中,我们就不需要再手动配置。
- 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可。
xxxxAutoConfigurartion:自动配置类;给容器中添加组件
xxxxProperties:封装配置文件中相关属性;