SpringBoot自动配置原理详解_第1页
SpringBoot自动配置原理详解_第2页
SpringBoot自动配置原理详解_第3页
SpringBoot自动配置原理详解_第4页
SpringBoot自动配置原理详解_第5页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第SpringBoot自动配置原理详解@SpringBootConfiguration(里面就是@Configuration,标注当前类为配置类,其实只是做了一层封装改了个名字而已)

@EnableAutoConfiguration(开启自动配置)

@ComponentScan(包扫描)

注:@Inherited是一个标识,用来修饰注解,如果一个类用上了@Inherited修饰的注解,那么其子类也会继承这个注解

我们下面逐一分析这3个注解作用

3.1.1@SpringBootConfiguration

我们继续点@SpringBootConfiguration进去查看源码如下:

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Configuration

@Indexed

public@interfaceSpringBootConfiguration{

@AliasFor(

annotation=Configuration.class

booleanproxyBeanMethods()defaulttrue;

@Configuration标注在某个类上,表示这是一个springboot的配置类。可以向容器中注入组件。

3.1.2@ComponentScan

@ComponentScan:配置用于Configuration类的组件扫描指令。

提供与SpringXML的context:component-scan元素并行的支持。

可以basePackageClasses或basePackages来定义要扫描的特定包。如果没有定义特定的包,将从声明该注解的类的包开始扫描。

3.1.3@EnableAutoConfiguration

@EnableAutoConfiguration顾名思义就是:开启自动导入配置

这个注解是SpringBoot的重点,我们下面详细讲解

四、@EnableAutoConfiguration

我们点进去看看该注解有什么内容

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@AutoConfigurationPackage//自动导包

@Import({AutoConfigurationImportSelector.class})//自动配置导入选择

public@interfaceEnableAutoConfiguration{

StringENABLED_OVERRIDE_PROPERTY="spring.boot.enableautoconfiguration";

Class[]exclude()default{};

String[]excludeName()default{};

4.1@AutoConfigurationPackage

自动导入配置包

点进去查看代码:

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@Import({Registrar.class})

public@interfaceAutoConfigurationPackage{

String[]basePackages()default{};

Class[]basePackageClasses()default{};

@Import为spring的注解,导入一个配置文件,在springboot中为给容器导入一个组件,而导入的组件由AutoConfigurationPackages.class的内部类Registrar.class执行逻辑来决定是如何导入的。

4.1.1@Import({Registrar.class})

点Registrar.class进去查看源码如下:

staticclassRegistrarimplementsImportBeanDefinitionRegistrar,DeterminableImports{

Registrar(){

publicvoidregisterBeanDefinitions(AnnotationMetadatametadata,BeanDefinitionRegistryregistry){

//断点

AutoConfigurationPackages.register(registry,(String[])(newAutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(newString[0]));

publicSetObjectdetermineImports(AnnotationMetadatametadata){

returnCollections.singleton(newAutoConfigurationPackages.PackageImports(metadata));

注:Registrar实现了ImportBeanDefinitionRegistrar类,就可以被注解@Import导入到spring容器里。

这个地方打断点

运行可以查看到(String[])(newAutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(newString[0])的值为com.ljw.springbootwork:当前启动类所在的包名

结论:@AutoConfigurationPackage就是将主配置类(@SpringBootApplication标注的类)所在的包下面所有的组件都扫描注冊到spring容器中。

4.2

@Import({AutoConfigurationImportSelector.class})

作用:AutoConfigurationImportSelector开启自动配置类的导包的选择器,即是带入哪些类,有选择性的导入

点AutoConfigurationImportSelector.class进入查看源码,这个类中有两个方法见名知意:

1.selectImports:选择需要导入的组件

publicString[]selectImports(AnnotationMetadataannotationMetadata){

if(!this.isEnabled(annotationMetadata)){

returnNO_IMPORTS;

}else{

AutoConfigurationImportSelector.AutoConfigurationEntryautoConfigurationEntry=this.getAutoConfigurationEntry(annotationMetadata);

returnStringUtils.toStringArray(autoConfigurationEntry.getConfigurations());

2.getAutoConfigurationEntry:根据导入的@Configuration类的AnnotationMetadata返回AutoConfigurationImportSelector.AutoConfigurationEntry

protectedAutoConfigurationImportSelector.AutoConfigurationEntrygetAutoConfigurationEntry(AnnotationMetadataannotationMetadata){

if(!this.isEnabled(annotationMetadata)){

returnEMPTY_ENTRY;

}else{

AnnotationAttributesattributes=this.getAttributes(annotationMetadata);

//这打个断点,看看返回的数据

ListStringconfigurations=this.getCandidateConfigurations(annotationMetadata,attributes);

//删除重复项

configurations=this.removeDuplicates(configurations);

SetStringexclusions=this.getExclusions(annotationMetadata,attributes);

//检查

this.checkExcludedClasses(configurations,exclusions);

//删除需要排除的依赖

configurations.removeAll(exclusions);

configurations=this.getConfigurationClassFilter().filter(configurations);

this.fireAutoConfigurationImportEvents(configurations,exclusions);

returnnewAutoConfigurationImportSelector.AutoConfigurationEntry(configurations,exclusions);

this.getCandidateConfigurations(annotationMetadata,attributes)这里断点查看

configurations数组长度为133,并且文件后缀名都为**AutoConfiguration

结论:这些都是候选的配置类,经过去重,去除需要的排除的依赖,最终的组件才是这个环境需要的所有组件。有了自动配置,就不需要我们自己手写配置的值了,配置类有默认值的。

我们继续往下看看是如何返回需要配置的组件的

4.2.1getCandidateConfigurations(annotationMetadata,attributes)

方法如下:

protectedListStringgetCandidateConfigurations(AnnotationMetadatametadata,AnnotationAttributesattributes){

ListStringconfigurations=SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(),this.getBeanClassLoader());

Assert.notEmpty(configurations,"NoautoconfigurationclassesfoundinMETA-INF/spring.factories.Ifyouareusingacustompackaging,makesurethatfileiscorrect.");

returnconfigurations;

这里有句断言:Assert.notEmpty(configurations,"NoautoconfigurationclassesfoundinMETA-INF/spring.factories.Ifyouareusingacustompackaging,makesurethatfileiscorrect.");

意思是:“在META-INF/spring.factories中没有找到自动配置类。如果您使用自定义包装,请确保该文件是正确的。“

结论:即是要loadFactoryNames()方法要找到自动的配置类返回才不会报错。

getSpringFactoriesLoaderFactoryClass()

我们点进去发现:this.getSpringFactoriesLoaderFactoryClass()返回的是EnableAutoConfiguration.class这个注解。这个注解和@SpringBootApplication下标识注解是同一个注解。

protectedClassgetSpringFactoriesLoaderFactoryClass(){

returnEnableAutoConfiguration.class;

结论:获取一个能加载自动配置类的类,即SpringBoot默认自动配置类为EnableAutoConfiguration

4.2.2SpringFactoriesLoader

SpringFactoriesLoader工厂加载机制是Spring内部提供的一个约定俗成的加载方式,只需要在模块的META-INF/spring.factories文件,这个Properties格式的文件中的key是接口、注解、或抽象类的全名,value是以逗号“,“分隔的实现类,使用SpringFactoriesLoader来实现相应的实现类注入Spirng容器中。

注:会加载所有jar包下的classpath路径下的META-INF/spring.factories文件,这样文件不止一个。

loadFactoryNames()

publicstaticListStringloadFactoryNames(ClassfactoryType,@NullableClassLoaderclassLoader){

ClassLoaderclassLoaderToUse=classLoader;

if(classLoaderToUse==null){

classLoaderToUse=SpringFactoriesLoader.class.getClassLoader();

StringfactoryTypeName=factoryType.getName();

returnloadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName,Collections.emptyList());

断点查看factoryTypeName:

先是将EnableAutoConfiguration.class传给了factoryType

然后StringfactoryTypeName=factoryType.getName();,所以factoryTypeName值为

org.springframework.boot.autoconfigure.EnableAutoConfiguration

loadSpringFactories()

接着查看loadSpringFactories方法的作用

privatestaticMapString,ListStringloadSpringFactories(ClassLoaderclassLoader){

//断点查看

MapString,ListStringresult=cache.get(classLoader);

if(result!=null){

returnresult;

result=newHashMap();

try{

//注意这里:META-INF/spring.factories

EnumerationURLurls=classLoader.getResources(FACTORIES_RESOURCE_LOCATION);

while(urls.hasMoreElements()){

URLurl=urls.nextElement();

UrlResourceresource=newUrlResource(url);

Propertiesproperties=PropertiesLoaderUtils.loadProperties(resource);

for(Map.Entry,entry:properties.entrySet()){

StringfactoryTypeName=((String)entry.getKey()).trim();

String[]factoryImplementationNames=

StringUmaDelimitedListToStringArray((String)entry.getValue());

for(StringfactoryImplementationName:factoryImplementationNames){

//断点

puteIfAbsent(factoryTypeName,key-newArrayList())

.add(factoryImplementationName.trim());

//Replacealllistswithunmodifiablelistscontaininguniqueelements

//去重,断点查看result值

result.replaceAll((factoryType,implementations)-implementations.stream().distinct()

.collect(Collectors.collectingAndThen(Collectors.toList(),Collections::unmodifiableList)));

cache.put(classLoader,result);

catch(IOExceptionex){

thrownewIllegalArgumentException("Unabletoloadfactoriesfromlocation["+

FACTORIES_RESOURCE_LOCATION+"]",ex);

returnresult;

这里的FACTORIES_RESOURCE_LOCATION在上面有定义:META-INF/spring.factories

publicfinalclassSpringFactoriesLoader{

*Thelocationtolookforfactories.

*pCanbepresentinmultipleJARfiles.

publicstaticfinalStringFACTORIES_RESOURCE_LOCATION="META-INF/spring.factories";

META-INF/spring.factories文件在哪里??

在所有引入的java包的当前类路径下的META-INF/spring.factories文件都会被读取,如:

断点查看result值如下:

该方法作用是加载所有依赖的路径META-INF/spring.factories文件,通过map结构保存,key为文件中定义的一些标识工厂类,value就是能自动配置的一些工厂实现的类,value用list保存并去重。

在回看loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName,Collections.emptyList());

因为loadFactoryNames方法携带过来的第一个参数为EnableAutoConfiguration.class,所以factoryType值也为EnableAutoConfiguration.class,那么factoryTypeName值为EnableAutoConfiguration。拿到的值就是META-INF/spring.factories文件下的key为

org.springframework.boot.autoconfigure.EnableAutoConfiguration的值

getOrDefault当Map集合中有这个key时,就使用这个key值,如果没有就使用默认值空数组

结论:

loadSpringFactories()该方法就是从“META-INF/spring.factories”中加载给定类型的工厂实现的完全限定类名放到map中

loadFactoryNames()是根据SpringBoot的启动生命流程,当需要加载自动配置类时,就会传入org.springframework.boot.autoconfigure.EnableAutoConfiguration参数,从map中查找key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的值,这些值通过反射加到容器中,之后的作用就是用它们来做自动配置,这就是Sp

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论