springboot自动装配原理详解,springboot自动装配原理简书
00-1010约定比配置自动组装编写一个启动组件要好。
目录
跳趾的保留优于配置主要表现在以下几个方面:Maven的目录结构:
默认情况下,配置文件存储在resources目录中,项目的编译文件存储在目标目录中。项目默认打包为jar格式,配置文件默认为application.yml或application.yaml或application.properties。
默认的spring.profiles.active属性决定了运行时环境的配置文件。
00-1010相比传统Spring项目繁琐的配置,SpringBoot项目只需要使用一个@SpringBootApplication注释就可以成功运行。没有安静的时间,只是有人在为我们负重前行。我们来看看@SpringBootApplication注释背后SpringBoot为我们做了什么。
可以看出@SpringBootApplication是一个组合标注,上面四个标注不用看,因为需要定义一个标注。关键在于以下三个注解@ spring boot configuration ``@ enable auto configuration ` `@ components can。也就是说,我们可以在没有@SpringBootApplication的情况下,使用这三个注释成功运行一个SpringBoot应用程序。
@SpringBootConfiguration评论
@ target(element type . type)@ retention(retention policy . runtime)@ documented @Configuration public @ interface spring boot Configuration { }点开源代码一看,其实是一个@ Configuration的注释。@配置应该大家都不陌生。有了这个注释,当前的类将由Spring管理。
@ComponentScan评论
该注释用于定义Spring的扫描路径,相当于context:component-scan。如果没有配置扫描路径,那么SpringBoot将默认扫描当前类的所有包及其标有需要管理的类的子包。
@启用自动配置
这个标注是跳靴自动装配的关键,也是组合标注。
@Target(ElementType。TYPE)@ Retention(Retention policy。RUNTIME)@ documentated @ Inherited @ auto configuration package @ Import(autoconfigurationimportselector . class)public @ interface enable auto configuration { String ENABLED _ OVERRIDE _ PROPERTY= spring . boot . enable auto configuration ;班级?[]排除()默认{ };string[]exclude name()default { };}@AutoConfigurationPackage实际上是一个@Import注释。
@ target(element type . type)@ retention(retention policy . runtime)@ documentated @ input(auto configuration packages . registrar . class)public @ interface自动配置包{} @ import注释
在标有@Configuration的类上,可以使用@Import引入其他配置类。其实也可以引入org . spring framework . context . annotation . import selector实现类。ImportSel
ector接口只定义了一个selectImports()
,用于指定需要注册为bean的Class名称。当在@Configuration
标注的Class上使用@Import
引入了一个ImportSelector
实现类后,会把实现类中返回的Class名称都定义为bean。
@EnableAutoConfiguration
中@Import
主要就是为了导入一个AutoConfigurationImportSelector
,下面我们分析一下这个类:
AutoConfigurationImportSelector类
AutoConfigurationImportSelect
类实现了ImportSelector
接口,所以我们清楚只需关注selectImports()
方法的返回结果即可:
@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());}该方法返回的是要注册到IOC容器中的对象的类型的全路径名称的字符串数组,所以我们要分析一下这个数组是从哪里来的?
进入到getAutoConfigurationEntry
方法中:
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;} // 获取注解的属性信息AnnotationAttributes attributes = getAttributes(annotationMetadata); // 获取候选配置List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);configurations = removeDuplicates(configurations);Set<String> exclusions = getExclusions(annotationMetadata, attributes);checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);configurations = filter(configurations, autoConfigurationMetadata);fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);}通过DEBUG可以看到,在
getCandidateConfigurations
方法中获取到了很多java类全路径
进入getCandidateConfigurations方法,可以看到有一个断言:如果configurations为空的话,会提示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
文件中,并且我们可以通过在正确的路径下面添加这个文件来自定义包来适配SpringBoot
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;}进入这个文件可以看到,这里配置了大量的需要自动装配的类,当我们启动Springboot项目的时候,SpringBoot会扫描所有jar包下面的
META-INF/spring.factories
文件,并根据key进行读取,在经过一系列的操作来完成自动装配。
需要注意的是:上图中的 spring.factories
文件是在 spring-boot-autoconfigure
包下面,这个包记录了官方提供的 stater 中几乎所有需要的自动装配类,所以并不是每一个官方的 starter 下都会有 spring.factories
文件。
@AutoConfigurationPackage注解
@AutoConfigurationPackage注解的主要作用就是将主程序类所在包及所有子包下的组件到扫描到spring容器中。
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Import(AutoConfigurationPackages.Registrar.class)public @interface AutoConfigurationPackage {}这个注解实际上是导入了
AutoConfigurationPackages
的一个内部类Registrar
,这个类的作用就是读取到最外层@SpringBootApplication
注解中配置的扫描路径(没有配置默认当前所在包),将该路径下所有文件扫描,并分析注册bean。
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {register(registry, new PackageImport(metadata).getPackageName());}@Overridepublic Set<Object> determineImports(AnnotationMetadata metadata) {return Collections.singleton(new PackageImport(metadata));}}
手写一个starter组件
上面提到在自己的包中添加META-INF/spring.factories
文件就可以适配SpringBoot实现自动配置,这其实是一种SPI的思想。SPI,Service Provider Interface。即:接口服务的提供者。就是说我们应该面向接口(抽象)编程,而不是面向具体的实现来编程,这样一旦我们需要切换到当前接口的其他实现就无需修改代码。
starter的命名规范:
官方的starter命名格式为spring-boot-starter-{xxx}
,例如:spring-boot-starter-web
等
自定义starter命名格式一般为{xxx}-spring-boot-starter
,例如mybatis的mybatis-spring-boot-starter
1) 新建一个springboot项目myself-spring-boot-starter
2) 新建自己的业务类
public class MyselfService { private String myself; // ……省略 getter setter public String doBusiness(Object obj){ return myself+obj.toString(); }}3)业务需要的一些属性值
@ConfigurationProperties("myself")public class MysefProperties { private String myself; // ……省略 getter setter}4)新建自动装配类,把自己的业务交给Spring管理
@Configuration@EnableConfigurationProperties(MysefProperties.class)public class MyselfAutoConfiguration { @Autowired MysefProperties mysefProperties; @Bean @ConditionalOnMissingBean(MyselfService.class) public MyselfService myselfService(){ MyselfService myselfService = new MyselfService(); myselfService.setMyself(mysefProperties.getMyself()); return myselfService; }}5)在resources/META-INF下新建spring.factories,配置starter中配置类的位置
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.yy.autoconfigure.MyselfAutoConfiguration6)mvn install将自己的包打到自己仓库中,在另外的项目直接引用即可
7)测试
mybatis-plus-boot-starter
我们可以学习一下其他第三方的成熟的starter,会发现其实套路是很相似的
到此这篇关于SpringBoot详细分析自动装配原理并实现starter的文章就介绍到这了,更多相关SpringBoot自动装配原理内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。