文章目录

  • @EnableAutoConfiguration介绍
  • AutoConfigurationImportSelector
    • 例子:使用importSelector
  • 自动装配原理分析
  • 总结

@EnableAutoConfiguration介绍

自动装配在Spring Boot中是通过@EnableAutoConfiguration注解来开启的,这个注解的声明在启动类注解@SpringBootApplication内。 进入@SpringBootApplication注解,可以看到@EnableAutoConfiguration注解的声明。

其实Spring 3.1版本就已经支持@Enable注解了,它的主要作用把相关组件的Bean装配到IoC容器中。
**@Enable注解对JavaConfig的进一步完善,为使用Spring Framework的开发者减少了配置代码量,降低了使用的难度。**比如常见的@Enable注解有@EnableWebMvc、@EnableScheduling等。

如果基于JavaConfig的形式来完成Bean的装载,则必须要使用@Configuration注解及@Bean注解。而@Enable本质上就是针对这两个注解的封装,所以大家如果仔细关注过这些注解,就不难发现这些注解中都会携带一个@Import注解,比如@EnableScheduling:因此,使用@Enable注解后,Spring会解析到@Import导入的配置类,从而根据这个配置类中的描述来实现Bean的装配,那么@EnableAutoConfiguraion实现原理是不是也一样呢?

进入@EnableAutoConfiguration注解里,可以看到除@Import注解之外,还多了一个@AutoConfigurationPackage注解(它的作用是把使用了该注解的类所在的包及子包下所有组件扫描到Spring IoC容器中)。并且,**@Import注解中导入的并不是一个Configuration的配置类,而是一个AutoConfigurationImportSelector类。**从这一点来看,它就和其他的@Enable注解有很大的不同。


@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};
}

AutoConfigurationImportSelector

AutoConfigurationImportSelector源码:

public class AutoConfigurationImportSelectorimplements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,BeanFactoryAware, EnvironmentAware, Ordered {private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();private static final String[] NO_IMPORTS = {};private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";private ConfigurableListableBeanFactory beanFactory;private Environment environment;private ClassLoader beanClassLoader;private ResourceLoader resourceLoader;....}

它实现了DeferredImportSelector,接口,而DeferredImportSelector又继承了ImportSelector,

package org.springframework.context.annotation;import org.springframework.core.type.AnnotationMetadata;public interface ImportSelector {String[] selectImports(AnnotationMetadata var1);
}

它只有一个selectImports抽象方法,并且返回一个String数组,在这个数组中可以指定需要装配到IoC容器的类,当在@Import中导入一个ImportSelector的实现类之后,会把该实现类中返回的Class名称都装载到IoC容器中。 和@Configuration不同的是,ImportSelector可以实现批量装配,并且还可以通过逻辑处理来实现Bean的选择性装配,也就是可以根据上下文来决定哪些类能够被IoC容器初始化。
其中DeferredImportSelector有一个方法:

 @Nullabledefault Class<? extends Group> getImportGroup() {return null;}

其执行逻辑是,当实现DeferredImportSelector类重写了

public Class<? extends Group> getImportGroup()
方法时,则在此类被@Import注解导入时执行getImportGroup方法,如果没有实现getImportGroup方法,则执行

public String[] selectImports(AnnotationMetadata importingClassMetadata)

例子:使用importSelector

1.先创建两个类

public class FirstClass {}
public class SecondClass {}

2.我们需要把这两个类装配到IoC容器中。 ·
创建一个ImportSelector的实现类,在实现类中把定义的两个Bean加入String数组,这意味着这两个Bean会装配到IoC容器中。 ·

/*** @Author* @Description importselector实现类,用于把自定义的类加入bean数组* @Date**/
public class GpImportSelector implements ImportSelector {@Overridepublic String [] selectImports(AnnotationMetadata metadata){return new String[]{FirstClass.class.getName(),SecondClass.class.getName()};}
}

3.为了模拟EnableAutoConfiguration,我们可以自定义一个类似的注解,通过@Import导入GpImportSelector。


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(GpImportSelector.class)
public @interface MyEnableleImport {}

4.· 创建一个启动类,在启动类上使用@EnableAutoImport注解后,即可通过getBean从IoC容器中得到FirstClass对象实例。

@MyEnableleImport
@SpringBootApplicationpublic class HwMusicApplication {public static void main(String[] args) throws IOException {ConfigurableApplicationContext ca = SpringApplication.run(HwMusicApplication.class, args);FirstClass firstClass = ca.getBean(FirstClass.class);firstClass.get();//自己随意写的一个方法}}

这种实现方式相比@Import(*Configuration.class)的好处在于装配的灵活性,还可以实现批量。比如GpImportSelector还可以直接在String数组中定义多个Configuration类,由于一个配置类代表的是某一个技术组件中批量的Bean声明,所以在自动装配这个过程中只需要扫描到指定路径下对应的配置类即可。

自动装配原理分析

自动装配的核心是扫描约定目录下的文件进行解析,解析完成之后把得到的Configuration配置类通过ImportSelector进行导入,从而完成Bean的自动装配过程。那么接下来我们通过分析AutoConfigurationImportSelector的实现来求证这个猜想是否正确。
定位到AutoConfigurationImportSelector中的selectImports方法,它是ImportSelector接口的实现,这个方法中主要有两个功能:

· AutoConfigurationMetadataLoader.loadMetadata

从META-INF/spring-autoconfigure-metadata.properties中加载自动装配的条件元数据,简单来说就是只有满足条件的Bean才能够进行装配。

· 收集所有符合条件的配置类
autoConfigurationEntry.getConfigurations(),完成自动装配。

 @Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}

该类的其他方法:
· getAttributes获得@EnableAutoConfiguration注解中的属性exclude、excludeName等。 ·
getCandidateConfigurations获得所有自动装配的配置类

 protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,AnnotationAttributes attributes) {List<String> 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;}

· removeDuplicates去除重复的配置项。

· getExclusions根据@EnableAutoConfiguration注解中配置的exclude等属性,把不需要自动装配的配置类移除。 ·

fireAutoConfigurationImportEvents广播事件。

· 最后返回经过多层判断和过滤之后的配置类集合。

总的来说,它先获得所有的配置类,通过去重、exclude排除等操作,得到最终需要实现自动装配的配置类。这里需要重点关注的是getCandidateConfigurations,它是获得配置类最核心的方法。 这里用到了SpringFactoriesLoader,它是Spring内部提供的一种约定俗成的加载方式,类似于Java中的SPI。简单来说,它会扫描classpath下的META-INF/spring.factories文件,spring.factories文件中的数据以Key=Value形式存储,而SpringFactoriesLoader.loadFactoryNames会根据Key得到对应的value值。因此,在这个场景中,Key对应为EnableAutoConfiguration,Value是多个配置类,也就是getCandidateConfigurations方法所返回的值。

总结

▶▶▶▶@EnableAutoConfiguraion上有一个@import注解,@Import注解中导入的并不是一个Configuration的配置类,而是一个AutoConfigurationImportSelector类,AutoConfigurationImportSelectori 实现了DeferredImportSelector, DeferredImportSelector继承了importSelector接口,实现了importSelector接口 重写了selectImports的类可以批量装载bean到ioc容器中

▶▶▶▶· 通过Spring提供的SpringFactoriesLoader机制,扫描classpath路径下的META-INF/spring.factories,读取需要实现自动装配的配置类。 ·
▶▶▶▶通过条件筛选的方式,把不符合条件的配置类移除,最终完成自动装配。 (@Conditional条件装配)

【学习笔记】springboot的AutoConfigurationImportSelector 、@EnableAutoConfiguraion和@import解析相关推荐

  1. Python学习笔记:列表、字典与集合解析(List, Dict and Set Comprehensions)

    Python学习笔记:列表.字典与集合解析(List, Dict and Set Comprehensions) 1.列表解析 最受喜爱的Python语言特性.过滤一个集合的元素生成一个新的列表. 一 ...

  2. Kubernetes学习笔记之Calico CNI Plugin源码解析(二)

    女主宣言 今天小编继续为大家分享Kubernetes Calico CNI Plugin学习笔记,希望能对大家有所帮助. PS:丰富的一线技术.多元化的表现形式,尽在"360云计算" ...

  3. Kubernetes学习笔记之Calico CNI Plugin源码解析(一)

    女主宣言 今天小编为大家分享Kubernets Calico CNI Plugin的源码学习笔记,希望对正在学习k8s相关部分的同学有所帮助: PS:丰富的一线技术.多元化的表现形式,尽在" ...

  4. 学习笔记——SpringBoot使用nutz框架时报错

    学习SpringBoot: 1.Impl文件下,注入dao报错. 1.注入dao时报错: 报错内容:'org.nutz.dao.Dao' that could not be found. 解决:pom ...

  5. 学习笔记 | SpringBoot微信点餐系统实战课程笔记(一)、数据库设计与创建

    本系列是用于记录学习慕课网廖师兄的<新版微服务时代Spring Boot企业微信点餐系统>实战课程的实战中的遇到的问题.疑惑.重点笔记等.文章可能不成条理,请见谅.欢迎多多交流学习~ 0. ...

  6. JavaEE学习笔记-SpringBoot快速上手、热部署、乱码问题、部分注解解释

    SpringBoot快速上手 一.快速创建SpringBoot应用 1.1利用IDEA提供的Spring Initializr创建Spring Boot应用 1.2Spring Boot生成的项目结构 ...

  7. python爬虫学习笔记-网络爬虫的三种数据解析方式

    爬虫的分类 1.通用爬虫:通用爬虫是搜索引擎(Baidu.Google.Yahoo等)"抓取系统"的重要组成部分.主要目的是将互联网上的网页下载到本地,形成一个互联网内容的镜像备份 ...

  8. 【学习笔记】关于DOM4J:使用DOM4J解析XML文档

    一.概述 DOM4J是一个易用的.开源的库,用于XML.XPath和XSLT中.采用了Java集合框架并完全支持DOM.SAX.和JAXP. DOM4J最大的特色是使用大量的接口,主要接口都在org. ...

  9. 播放视频android学习笔记---44_在线视频播放器,网络视频解析器,SurfaceView 控件使用方法...

    最近用使开辟的过程中涌现了一个小题问,顺便录记一下因原和法方--播放视频 44_在线视频播放器 ------------------------- 1.注意这里,在模拟器中,android2.2和an ...

最新文章

  1. 【图论专题】单源最短路的扩展应用
  2. microsoft edge 打不开 csdn 博客
  3. NLP NER HMM CRF讲的较好的知乎
  4. 12C -- DDL日志
  5. Python pip安装命令
  6. 【APUE】文件 I/O 操作
  7. 135. 最大子序和【前缀和 单调队列】
  8. 到底什么是云计算-转自http://blog.csdn.net/adwu73
  9. Socket 编程 windows到Linux代码移植遇到的问题
  10. linux之dig命令
  11. 【词云】wordcloud安装与使用
  12. 一个简单的flask程序
  13. 将您重定向的次数过多。_吃鸡:蹦蹦将迎来新皮肤?体验服全面加强,最高时速也不打滑...
  14. 比勤奋更能决定人生的,是复利思维
  15. java.lang.IllegalArgumentException: Merged region H2 must contain 2 or more cells
  16. MAC更新系统网络连接中断
  17. python 列表写入excel_python怎么读取和写入excel表格
  18. WebApi系列~通过HttpClient来调用Web Api接口
  19. java垃圾回收简介
  20. ikea营销_用于企业的AI开发人员工具存在的问题(以及IKEA与之相关的问题)

热门文章

  1. java grizzly_Grizzly简介
  2. Java使用预定格式获取时间字符串
  3. 多特征值数据预处理_「人工智能」No.6 特征工程之数据预处理
  4. 计算机开机跳过硬盘检查,电脑开机后如何跳过磁盘检查过程?
  5. 期末考试前的预习,科目:化工设备与反应器(1)
  6. 十四、Java练习:一个猜数游戏
  7. sklearn分类模型
  8. sklearn 聚类 实例
  9. 我与AI:我的“机器学习”过程
  10. 对比学习(Contrastive Learning)相关进展梳理