引言
在SpringBoot中,自动配置减少了很多操作步骤;我们可以在SpringBoot主配置文件application.yml文件中配置很多属性,那么这些属性又是如何生效的?这就需要深入源码来探究一下底层原理了;
测试环境:
2022年2月13日,java版本:SDK16,springboot版本:2.6.3
开发工具:IDEA
(因为SpringBoot源码在不同版本下会有细微不同,但是大体都是相同的,跟着思路来都能走通)
走进源码
@SpringBootApplication
SpringBoot项目中都有一个启动类,启动类上都有注解:@SpringBootApplication
这也是项目启动的入口,就从这里作为起点,我们点进去看它的源码:
这里我们只看它的注解,发现有一个叫@EnableAutoConfiguration
的注解,直接翻译意思就是:启用自动配置,那么自动配置肯定和它有关系;
@EnableAutoConfiguration
点进去@EnableAutoConfiguration
的源码:
它的源码就简单很多了,可以发现最后@Import中导入了AutoConfigurationImportSelector.class
,同样直译出来:自动配置导入选择器,因为我们并不是把springboot中的所有配置都导入的,那么配置选择性的自动导入肯定和这个类有关系;
AutoConfigurationImportSelector.class
selectImports()
点进去AutoConfigurationImportSelector.class
的源码,可以看到构造方法下面的第一个方法是:selectImports
方法,意思是选择导入;
其实读源码需要考验英语能力,可以看到该方法中调用了一个getAutoConfigurationEntry
方法,直译就是:获取自动配置条目
getAutoConfigurationEntry()
转到getAutoConfigurationEntry
方法,这个方法也在AutoConfigurationImportSelector
类中:
这个方法中有一个List集合:configurations
,那么所有的配置都应该是加载到了这个集合当中,从而可以定位到给configurations
赋值的方法:getCandidateConfigurations
方法,直译为:得到候选配置
getCandidateConfigurations()
进入getCandidateConfigurations
方法,该方法同样在AutoConfigurationImportSelector
类中:
这个方法其实就可以看到配置是从哪里加载的了,
首先所有需要的配置都是通过SpringFactoriesLoader
类的loadFactoryNames
方法中获取的,在分析这个类之前可以看到下面的notEmpty方法中有一句话:
"No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct."
直译就是:在META-INF/spring.factories中找不到自动配置类。如果您正在使用自定义打包,请确保该文件是正确的。”
这不就直接定位到配置类加载的文件夹了嘛,就是META-INF/spring.factories,但是这里也只能推断一下,下面我们看一下SpringFactoriesLoader
类的源码;
SpringFactoriesLoader.class
进入这个类的源码,开始就能看到:
FACTORIES_RESOURCE_LOCATION
直译就是工厂资源位置,就是配置文件的位置,也印证了上面的猜测,配置类就是在META-INF/spring.factories下面;
当然这还没有完,可以再简单看一下刚才用到的loadFactoryNames
方法:
发现它返回的配置是通过loadSpringFactories
方法获取的,继续深入该方法:
loadSpringFactories
方法就是从META-INF/spring.factories文件中加载的配置;
确定配置文件的位置,下面就是去找这些配置文件;
META-INF/spring.factories
libraries有很多jar包
找到一个叫spring-boot-autoconfigure
的包:
点开就可以找到spring.factories文件了;
在Auto Configure部分中每一个xxxAutoConfiguration类都是容器中的一个组件,并且都会加入到容器中,在这些自动配置类都是在某些条件之下才会生效,这些
条件的限制在Spring Boot中以注解的形式体现,就比如:
- @ConditionalOnClass:当类路径下有指定类的条件下生效
- @ConditionalOnMissingBean:当容器里不存在指定bean的条件下生效
可以点开几个看看源码上的注解,多看几个就找到共同点了;
application.yml配置文件如何联系到spring.factories
那么到底主配置文件何spring.factories文件是如何联系的?
这里就以spring.factories文件中的WebServicesAutoConfiguration.class
为例
只看注解,发现有一个@EnableConfigurationProperties
注解,开启配置属性,而它后面的参数是一个WebServicesProperties
类;
@EnableConfigurationProperties
的功能是进入WebServicesProperties
中查看,将配置文件中对应的值和WebServicesProperties
绑定起来,并把WebServicesProperties
加入到 IOC 容器中;
在这个类上有一个@ConfigurationProperties
注解,它的作用就是从配置文件中绑定属性到对应的bean上,而前面的
@EnableConfigurationProperties
注解把这个已经绑定了属性的bean导入到 IOC 容器中,那么所有和这个类相关的属性都可以在主配置文件application.yml中定义;
总结
Spring Boot启动的时候会通过@EnableAutoConfiguration
注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在主配置文件中配置的属性如:spring.mvc.format.date
,而xxxxProperties类是通过@ConfigurationProperties
注解与主配置文件application.yml中对应的属性进行绑定的;
所以以后在主配置文件application.yml中配置属性时,如果对用法不了解,就可以直接进入对应的xxxxAutoConfigurartion自动配置类中,再同过它找到对应的xxxxProperties类,从中可以找到需要的属性;
读源码的能力还是需要一步一步的培养出来,慢慢起步,总有一天会有所积累的;