为什么要 starter ?
Spring Boot Starter 的 POM 文件中,引入了各种 jar 文件,当你想拥有某个功能的时候,引入 starter 即可。
比如 常见的 starter 有 spring-boot-starter-web、spring-boot-starter-test、spring-boot-starter-jdbc,将这些 starter 添加到 POM 文件中,就拥有了对应了能力。
自定义 starter
样例:自定义一个 starter,通过配置文件,输出姓名和年龄
添加依赖
<?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.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>CustomSpringBootStarter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>CustomSpringBootStarter</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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
新建服务类
用于调用测试
public class TestService {
private String name;
private int age;
public TestService(String name, int age) {
this.name = name;
this.age = age;
}
public void test(){
System.out.println("Hello " + name + ", your age is " + age);
}
}
新建属性配置类
读取配置文件
@ConfigurationProperties(prefix = "start")
public class TestProperties {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
编写自动配置类
@Configuration
@ConditionalOnClass(TestService.class)
@EnableConfigurationProperties(TestProperties.class)
public class TestServiceConfiguration {
@Autowired
private TestProperties testProperties;
@Bean
@ConditionalOnMissingBean
public TestService testService(){
return new TestService(testProperties.getName(),testProperties.getAge());
}
}
添加配置管理
starter 配置分为被动生效和主动生效两种场景,被动生效就是当它被添加到依赖的项目中时,自动被装载到 Spring 容器中;而主动生效则需要主动声明 starter 才会将 starter 里面声明的 Bean 添加到 Spring 容器中。
- 被动生效,依赖时就生效
在 resource/META-INF/ 目录下面,新建 spring.factories 文件
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.customspringbootstarter.configuration.TestServiceConfiguration
- 主动生效
自定义注解,通过 @Import 将配置类引入进来。
测试时需要在启动类上加上该注解才能生效
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(TestServiceConfiguration.class)
public @interface EnableTest {
}
测试验证 starter
仅验证 starter 被动生效场景
-
新建 Spring Boot 项目,添加上面 starter 依赖
<dependency> <groupId>com.example</groupId> <artifactId>CustomSpringBootStarter</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
-
application.properties 配置
start.age = 18 start.name=Answer
-
运行 Main 函数进行测试输出
@SpringBootApplication
public class CutomerSpringBootStarterTestApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(CutomerSpringBootStarterTestApplication.class, args);
}
@Autowired
private TestService testService;
@Override
public void run(String... args) throws Exception {
testService.test();
}
}
输出:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.3)
2021-08-02 13:43:04.480 INFO 14400 --- [ main] .CutomerSpringBootStarterTestApplication : Starting CutomerSpringBootStarterTestApplication using Java 1.8.0_211 on Answer with PID 14400 (C:\Users\answer\Documents\CutomerSpringBootStarterTest\target\classes started by answer in C:\Users\answer\Documents\CutomerSpringBootStarterTest)
2021-08-02 13:43:04.483 INFO 14400 --- [ main] .CutomerSpringBootStarterTestApplication : No active profile set, falling back to default profiles: default
2021-08-02 13:43:05.115 INFO 14400 --- [ main] .CutomerSpringBootStarterTestApplication : Started CutomerSpringBootStarterTestApplication in 1.362 seconds (JVM running for 3.115)
Hello Answer, your age is 18
总结
starter 主动生效与被动生效:若在 META-INF/spring.factories 中指定了配置类,那么 starter 将自动被装载到 Spring 容器中;否则需要通过 @Import 方式将配置类装载到 Spring 容器中。
命名规范:自己写的 starter 命名规则建议为 {name}-spring-boot-starter,Spring 官方 starter 的命名通常为 spring-boot-starter-{name}
自动装配流程:Spring Boot 扫描依赖包中的 spring.factories 文件,加载 EnableAutoConfiguration 指定的配置类,将配置类里面的 Bean 加载到 Spring 容器中。