深入理解SpringBoot核心机制《spring-boot-starter》
前言:
对于这几年java火爆天的springBoot我相信大家都有所使用过,在springBoot的项目中,pom文件引入最多的无非就是各种各样的srping-starter了。
什么是 Starter 呢?为什么要使用Starter呢?
你可以理解为一个可拔插式的插件(组件)。
通过 Starter,能够简化以前繁琐的配置,无需过多的配置和依赖,它会帮你合并依赖,并且将其统一集成到一个 Starter 中,我们只需在 Maven 或 Gradle 中引入 Starter 依赖即可。SpringBoot 会自动扫描需要加载的信息并启动相应的默认配置。
如果你想使用 redis 插件,你只需引入 spring-boot-starter-data-redis 即可;如果你想使用 mongodb,你只需引入 spring-boot-starter-data-mongodb 依赖即可。
springBoot-starter是一个集成接合器,完成两件事:
1、引入模块所需的相关jar包
2、自动配置各自模块所需的属性
SpringBoot 官方提供了大量日常企业应用研发各种场景的 spring-boot-starter 依赖模块。这些依赖模块都遵循着约定成俗的默认配置,并允许我们根据自身情况调整这些配置。
官方git地址:https://github.com/spring-projects/spring-boot/tree/2.5.x/spring-boot-project/spring-boot-starters
starter启动原理:
使用过springBoot项目的人应该都对@SpringBootApplication注解有所了解,那么我们看下源码:
@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
其中@EnableAutoConfiguration注解源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration
可以从源码看出关键功能是@Import注解导入自动配置功能类AutoConfigurationImportSelector类,主要方法getCandidateConfigurations()使用了SpringFactoriesLoader.loadFactoryNames()方法加载META-INF/spring.factories的文件(spring.factories声明具体自动配置)。
自定义starter:
Starter 命名规则
Spring 官方定义的 Starter 通常命名遵循的格式为 spring-boot-starter-{name},例如 spring-boot-starter-data-mongodb。
Spring 官方建议,非官方 Starter 命名应遵循 {name}-spring-boot-starter 的格式,例如,myjson-spring-boot-starter。
pom文件配置如下:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.11.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.duxn</groupId>
<artifactId>duxn-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>duxn-spring-boot-starter</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
</dependencies>
<!-- 设置deploy的地址 -->
<distributionManagement>
<snapshotRepository>
<id>maven-snapshots</id>
<name>user snapshot</name>
<url>maven仓库地址</url>
</snapshotRepository>
<repository>
<id>maven-releases</id>
<name>user release resp</name>
<url>maven仓库地址/</url>
</repository>
</distributionManagement>
<build>
<finalName>${project.artifactId}-${project.version}</finalName>
<plugins>
<!-- 跳过测试用例 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
</project>
config配置如下:
public class BaseConfig {
@ConfigurationProperties(prefix = "fulu")
@Data
public static class FuluConfig {
public String ichnbUrl = "可以设置默认值";
public Boolean isCache = true;//是否缓存
public Boolean isAuth = false;//是否校验身份信息
}
@ConfigurationProperties(prefix = "jwt")
@Data
public static class JWTConfig {
public String issuer = "可以设置默认值";
public String url = "可以设置默认值";
}
@ConfigurationProperties(prefix = "jwt.rpc")
@Data
public static class JWTRPCConfig {
public String secret = "可以设置默认值";
}
@ConfigurationProperties(prefix = "oss")
@Data
public static class OSSConfig {
private String accessId = "可以设置默认值";
private String accessKey = "可以设置默认值";
private String endPoint = "可以设置默认值";
private String nameSpace = "可以设置默认值";
private String packages = "可以设置默认值";
}
}
核心配置类:
@Configuration
@AutoConfigureOrder(Integer.MAX_VALUE)
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnClass({HttpUtils.class})
@EnableConfigurationProperties({
BaseConfig.JWTConfig.class,
BaseConfig.JWTRPCConfig.class,
BaseConfig.FuluConfig.class,
BaseConfig.OSSConfig.class
})
@Slf4j
public class StarterConfiguration {
@Resource
private BaseConfig.JWTConfig jwtConfig;
@Resource
private BaseConfig.JWTRPCConfig jwtrpcConfig;
@Resource
private BaseConfig.FuluConfig fuluConfig;
@Resource
private BaseConfig.OSSConfig ossConfig;
@Bean
public HttpUtils httpUtils() {
return new HttpUtils(redisTemplate, jwtConfig, jwtrpcConfig, fuluConfig);
}
}
spring.factory配置:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.duxn.starter.config.StarterConfiguration
如需添加扫描可以在StarterConfiguration中注入@Bean或者直接在spring.factory追加扫描
假设扫描类需要添加构造入参则只能在StarterConfiguration中注入@Bean
此时一个spring-boot-starter已开发完毕。
使用方式:
pom文件引入
<dependency>
<groupId>com.duxn</groupId>
<artifactId>duxn-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
yml文件配置
fulu:
ichnbUrl:
isCache:
isAuth:
jwt:
issuer:
rpc:
secret:
url:
oss:
accessId:
accessKey:
endPoint:
nameSpace:
packages:
至此:一个自己的starer已完成!