springboot的starter原理,springboot starter核心组件

首页 > 经验 > 作者:YD1662022-10-29 11:58:07

该项目里面包含:pom.xml、application.properties、Application 和 TestRunner 文件。

先看看pom.xml文件

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <version>1.3.1</version> <groupId>com.sue</groupId> <artifactId>spring-boot-id-generate-test</artifactId> <name>spring-boot-id-generate-test</name> <dependencies> <dependency> <groupId>com.sue</groupId> <artifactId>id-generate-spring-boot-starter</artifactId> <version>1.3.1</version> </dependency> </dependencies> </project>

由于只测试刚刚定义的id生成功能,所以只引入的id-generate-spring-boot-starter jar包。

application.properties配置资源文件

sue.workId=123

只有一行配置,因为我们的IdProperties中目前只需要这一个参数。

Application是测试程序启动类

@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

很简单,就是一个普通的springboot启动类

TestRunner是我们的测试类

@Component public class TestRunner implements ApplicationRunner { @Autowired private IdGenerateService idGenerateService; public void run(ApplicationArguments args) throws Exception { Long sysNo = idGenerateService.generate(); System.out.println(sysNo); } }

它实现了ApplicationRunner接口,所以在springboot启动的时候会调用该类的run方法。

好了,所有自定义starter的代码和测试代码都已经就绪。接下,运行一下Application类的main方法。

运行结果:

176

完美,验证成功了。

接下来,我们分析一下starter的底层实现原理。

4 starter的底层原理是什么?

通过上面编写自己的starter的例子,相信大家对starter的认识更进一步了,现在跟大家一起看看starter的底层是如何实现的。

id-generate-starter.jar其实是一个空项目,依赖于id-generate-autoconfiguration.jar。

id-generate-starter.jar是一个入口,我们给他取一个更优雅的名字:门面模式,其他业务系统想引入相应的功能,必须要通过这个门面。

我们重点分析一下 id-generate-autoconfiguration.jar

该jar包核心内容是:IdGenerateConfiguration,这个配置类中创建了IdGenerateService对象,IdGenerateService是我们所需要自动配置的具体功能。

接下来一个最重要的问题:IdGenerateConfiguration为什么会自动加载的呢?

还记得我们定义的spring.factories文件不?

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.sue.IdGenerateAutoConfiguration

它里面只包含一行配置,其中key是EnableAutoConfiguration,value是IdGenerateAutoConfiguration。

要搞明白这个过程,要从Application类的@SpringBootApplication注解开始:

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { @AliasFor(annotation = EnableAutoConfiguration.class) Class<?>[] exclude() default {}; @AliasFor(annotation = EnableAutoConfiguration.class) String[] excludeName() default {}; @AliasFor(annotation = ComponentScan.class, attribute = "basePackages") String[] scanBasePackages() default {}; @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses") Class<?>[] scanBasePackageClasses() default {}; }

从上面可以看出该注解里面包含了@EnableAutoConfiguration注解。

@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 {}; }

@EnableAutoConfiguration注解会引入AutoConfigurationImportSelector类。

该类的selectImports方法一个关键方法:

@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { //配置有没有配置spring.boot.enableautoconfiguration开关,默认为true //如果为false,则不执行自动配置的功能,直接返回 if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } //找spring-autoconfigure-metadata.properties中的元素 AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); //获取EnableAutoConfiguration注解中的属性 AnnotationAttributes attributes = getAttributes(annotationMetadata); //获取工程下所有配置key为EnableAutoConfiguration的值,即IdGenerateConfiguration等类。 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 StringUtils.toStringArray(configurations); }

这里就是starter能够自动配置的秘密。

此外,有些朋友看其他人定义的springboot starter可能会有疑惑。

先看看druid-spring-boot-starter

springboot的starter原理,springboot starter核心组件(9)

alibaba定义的druid-spring-boot-starter只有xxx-spring-boot-starter.jar文件,而没有xxx-spring-boot-autoconfigure.jar文件。

再看看spring-boot-starter-jdbc:

springboot的starter原理,springboot starter核心组件(10)

更神奇的是这个文件中连pom.xml都没有,一脸懵逼。。。。。。。

是不是我讲错了?

答:其实没有。

SpringBoot的原则是约定优于配置。

从spring-boot-starter-jdbc内部空实现来看,它的约定是要把xxx-spring-boot-starter.jar和xxx-spring-boot-autoconfigure.jar区分开的。个人认为,alibaba定义得并不好,没有遵照springboot的约定,虽然功能不受影响。(这个地方欢迎一起探讨一下)

而springboot自己定义的spring-boot-starter-jdbc为什么连pom.xml文件也没有呢?

它不需要依赖xxx-spring-boot-autoconfigure.jar文件吗?

因为springboot把所有的自动配置的类都统一放到spring-boot-autoconfigure.jar下面了:

springboot的starter原理,springboot starter核心组件(11)

spring.factories文件内容如下:

springboot的starter原理,springboot starter核心组件(12)

上一页1234下一页

栏目热文

文档排行

本站推荐

Copyright © 2018 - 2021 www.yd166.com., All Rights Reserved.