starter是SpringBoot提供的便捷的自动装配组件,通过引入starter包,可以规避以前那种自己添加一大堆依赖,还需要自己注册Bean的方式。可以说是太方便了。
SpringBoot定义了很多常用的starter方便我们应用,官方定义的一般以spring-boot-starter-xxx格式命名,也有一些第三方软件自己定义的starter,这种一般以xxx-spring-boot-starter格式命名。
今天我们自己手撕一个starter。
starter一般分为两部分,一个starter包,一个autoconfiguration包。
starter包一般不包含任何代码,只负责引入一些依赖,比如autoconfiguration的依赖。
autoconfiguration负责定义配置类,自动装载,核心业务Bean。
也有人将所有内容豆丁一到starter包中。
autoconfiguration
首先我们创建一个项目demo-spring-boot-autoconfiguration
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 http://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.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.qiejk</groupId>
<artifactId>demo-spring-boot-autoconfiguration</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
创建一个配置文件类DemoProperties.java
// 这是一个配置文件类
@ConfigurationProperties(prefix = "demo")
public class DemoProperties {
private String name;
private String value;
public String getName() {
return name;
}
public DemoProperties setName(String name) {
this.name = name;
return this;
}
public String getValue() {
return value;
}
public DemoProperties setValue(String value) {
this.value = value;
return this;
}
}
创建一个核心业务类DemoService.java
// 这是一个工具类
public class DemoService {
private String name;
private String value;
public DemoService(String name, String value) {
this.name = name;
this.value = value;
System.out.println("DemoService init success!");
}
public String getName() {
return name;
}
public DemoService setName(String name) {
this.name = name;
return this;
}
public String getValue() {
return value;
}
public DemoService setValue(String value) {
this.value = value;
return this;
}
public void say() {
System.out.println(name + " say: " + value);
}
}
创建一个配置类DemoAutoConfiguration.java
@Configuration
// 引入配置文件类
@EnableConfigurationProperties(DemoProperties.class)
// 只有在配置了demo的配置信息时,才进行加载
@ConditionalOnProperty(prefix = "demo", value = "name")
public class DemoAutoConfiguration {
@Autowired
private DemoProperties properties;
@Bean
public DemoService demoService() {
return new DemoService(properties.getName(), properties.getValue());
}
}
在/resources/META-INF/目录下添加spring.factories文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.qiejk.demo.springboot.autoconfiguration.DemoAutoConfiguration
整体项目结构为:
image.png
执行 mvn clean install -Dskiptests 打包命令。
starter
首先我们创建一个项目demo-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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qiejk</groupId>
<artifactId>demo-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.qiejk</groupId>
<artifactId>demo-spring-boot-autoconfiguration</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
执行 mvn clean install -Dskiptests 打包命令。
验证starter
我们随便创建一个SpringBoot项目,引入我们定义的starter
<dependency>
<groupId>com.qiejk</groupId>
<artifactId>demo-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
@SpringBootApplication
public class SpringbootDemoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(SpringbootDemoApplication.class, args);
DemoService demoService = (DemoService)run.getBean("demoService");
demoService.say();
}
先不配置参数,直接启动,这里会抛出异常,没有找到demoService对象。
这里是因为我们上面的配置类中,配置了@ConditionalOnProperty(prefix = "demo", value = "name"),这行代码的意思是,只有在配置了demo.name的参数之后,才进行配置类的加载。
在配置文件application.properties中添加配置
demo.name=jack
demo.value=hello
再次启动
/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/bin/java -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=64253:/Applications/IntelliJ IDEA.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/tools.jar:/Users/qiejinkai/Work/Liepin/ideaspace/springboot-demo/target/classes:/Users/qiejinkai/Work/Liepin/mvn/org/springframework/boot/spring-boot-starter/2.5.1/spring-boot-starter-2.5.1.jar:/Users/qiejinkai/Work/Liepin/mvn/org/springframework/boot/spring-boot/2.5.1/spring-boot-2.5.1.jar:/Users/qiejinkai/Work/Liepin/mvn/org/springframework/spring-context/5.3.8/spring-context-5.3.8.jar:/Users/qiejinkai/Work/Liepin/mvn/org/springframework/spring-aop/5.3.8/spring-aop-5.3.8.jar:/Users/qiejinkai/Work/Liepin/mvn/org/springframework/spring-beans/5.3.8/spring-beans-5.3.8.jar:/Users/qiejinkai/Work/Liepin/mvn/org/springframework/spring-expression/5.3.8/spring-expression-5.3.8.jar:/Users/qiejinkai/Work/Liepin/mvn/org/springframework/boot/spring-boot-autoconfigure/2.5.1/spring-boot-autoconfigure-2.5.1.jar:/Users/qiejinkai/Work/Liepin/mvn/org/springframework/boot/spring-boot-starter-logging/2.5.1/spring-boot-starter-logging-2.5.1.jar:/Users/qiejinkai/Work/Liepin/mvn/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar:/Users/qiejinkai/Work/Liepin/mvn/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar:/Users/qiejinkai/Work/Liepin/mvn/org/apache/logging/log4j/log4j-to-slf4j/2.14.1/log4j-to-slf4j-2.14.1.jar:/Users/qiejinkai/Work/Liepin/mvn/org/apache/logging/log4j/log4j-api/2.14.1/log4j-api-2.14.1.jar:/Users/qiejinkai/Work/Liepin/mvn/org/slf4j/jul-to-slf4j/1.7.30/jul-to-slf4j-1.7.30.jar:/Users/qiejinkai/Work/Liepin/mvn/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar:/Users/qiejinkai/Work/Liepin/mvn/org/springframework/spring-core/5.3.8/spring-core-5.3.8.jar:/Users/qiejinkai/Work/Liepin/mvn/org/springframework/spring-jcl/5.3.8/spring-jcl-5.3.8.jar:/Users/qiejinkai/Work/Liepin/mvn/org/yaml/snakeyaml/1.28/snakeyaml-1.28.jar:/Users/qiejinkai/Work/Liepin/ideaspace/demo-spring-boot-starter/target/classes:/Users/qiejinkai/Work/Liepin/ideaspace/demo-spring-boot-autoconfiguration/target/classes:/Users/qiejinkai/Work/Liepin/mvn/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar com.qiejk.springbootdemo.SpringbootDemoApplication
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.1)
2021-07-09 09:20:39.020 INFO 23563 --- [ main] c.q.s.SpringbootDemoApplication : Starting SpringbootDemoApplication using Java 1.8.0_181 on bogon with PID 23563 (/Users/qiejinkai/Work/Liepin/ideaspace/springboot-demo/target/classes started by qiejinkai in /Users/qiejinkai/Work/Liepin/ideaspace/springboot-demo)
2021-07-09 09:20:39.030 INFO 23563 --- [ main] c.q.s.SpringbootDemoApplication : No active profile set, falling back to default profiles: default
DemoService init success!
2021-07-09 09:20:41.873 INFO 23563 --- [ main] c.q.s.SpringbootDemoApplication : Started SpringbootDemoApplication in 5.221 seconds (JVM running for 9.744)
jack say: hello
Process finished with exit code 0
OK! 搞定。
总结
- 自定义starter命名规范:xxx-spring-boot-starter
- starter组成为 一个starter包(负责引入依赖),一个autoconfiguration包(负责实现装配)
- autoconfiguration包定义对应的properties类,configuration类,核心业务类。
- autoconfiguration包的/resources/META-INF/目录下添加spring.factories文件,并配置
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.qiejk.demo.springboot.autoconfiguration.DemoAutoConfiguration
,这步是SpringBoot装配的核心,只有添加了这个内容,SpringBoot才会进行自动装配。
网友评论