一、介绍与定义
本章用于记录自定义Springboot-starter
的学习过程。
在我们自定义starter
之前,我们首先观察一下SpringBoot
自身的starter
的形式都是什么样的。我们以spring-boot-starter-web
为例。
通过spring-boot-starter-web
,可以看出当前引入的依赖是空的JAR
文件。它的作用是仅提供辅助依赖管理,这些依赖可用于自动装配或者其他类库。继续点入,可以看见其引入了spring-boot-starter
,再进一步点入,又能看见其引入了spring-boot-autoconfigure
。
<!-- 在spring-boot-starter-web中引入了以下依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.4.0</version>
<scope>compile</scope>
</dependency>
<!-- 在spring-boot-starter中引入了以下依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.4.0</version>
<scope>compile</scope>
</dependency>
从以上总结出,starter
的场景需要以下两个模块:
- 启动器模块 –
xx-starter
- 自动配置模块
自定义starters
,即对自动装配的组件交给SpringBoot
管理,继而供我们使用,需满足以下条件:
-
自动装配
Bean
自动装配使用配置类(
@Configuration
)结合Spring
提供的条件判断注解@Conditional
,即SpringBoot
的派生注解,如:@ConditionOnClass
完成; -
配置自动装配
Bean
将标注@
Configuration
的自动配置类,放在classpath
下META-INF/spring.factories
文件中。
同样,以WebMvcAutoConfiguration
为例的自动配置编写:
@Configuration //指定这个类是一个配置类
@ConditionalOnXXX //在指定条件成立的情况下自动配置类生效
@AutoConfigureAfter //指定自动配置类的顺序
@Bean //给容器中添加组件
@ConfigurationPropertie // 结合相关xxxProperties类来绑定相关的配置
@EnableConfigurationProperties //让xxxProperties生效加入到容器中
自动配置类要是能够加载,那么就需要将启动加载的自动配置类,配置在META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
所有自动配置:首先它是一个自动配置类;设定起作用的条件,再将相关配置加入到容器中。
启动器:启动器模块是一个空的JAR
文件,仅提供辅助性依赖管理,这些依赖用于自动装配或者其他类库。
总结starter
的使用模式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u9idr4iy-1617345063681)(https://s3.ax1x.com/2020/11/15/DF5vgP.png)]
首先编写xxx-starter
启动器,继续编写一个xxx-starter-autoconfigurer
自动配置类,我的启动器则依赖此自动配置类。当需要使用我们的starter
时,则只需要直接依赖我们的xxx-starter
启动器即可。
命名规范:
- 官方命名空间
- 前缀:
spring-boot-starter-
- 模式:
spring-boot-starter-模块名
- 例子:
spring-boot-starter-web
、spring-boot-starter-actuator
、spring-boot-starter-jdbc
- 前缀:
- 自定义命名空间
- 后缀:
-spring-boot-starter
- 模式:
模块-spring-boot-starter
- 举例:
mybatis-spring-boot-starter
- 后缀:
自定义starter
步骤:创建两个模块。一个作为启动器,一个作为自动配置模块。最终的目的,启动器中包含着自动配置模块,导入依赖时是导入启动器。
二、自定义Starter的编写
新建工程,创建两个模块。分别作为启动器模块和自动配置模块。自定义hello
的starter
。
启动器模块命名:selfdef-spring-boot-starter
。
自动配置模块:selfdef-spring-boot-starter-autoconfigurer
启动器模块:
按照之前的描述,启动器模块不写入任何内容,只在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>
<groupId>cn.chemlez</groupId>
<artifactId>selfdef-springboot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 启动器 -->
<dependencies>
<!-- 自动配置模块 -->
<dependency>
<groupId>cn.chemlez.starter</groupId>
<artifactId>selfdef-spring-boot-starter-autoconfigurer</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
自动配置模块:
<?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.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.chemlez.starter</groupId>
<artifactId>selfdef-spring-boot-starter-autoconfigurer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sefldef-spring-boot-starter-autoconfigurer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- 引入spring-boot-starter:所有starter的基本配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
编写配置类:
// 绑定属性,以 chemlez.hello 为开头的配置
@ConfigurationProperties(prefix = "chemlez.hello")
public class HelloProperties {
private String prefix;
private String suffix;
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
}
编写HelloService
类:
public class HelloService {
HelloProperties helloProperties;
public String sayHello(String name) {
return helloProperties.getPrefix() + "-" + name + helloProperties.getSuffix();
}
public HelloProperties getHelloProperties() {
return helloProperties;
}
public void setHelloProperties(HelloProperties helloProperties) {
this.helloProperties = helloProperties;
}
}
供调用starter
的使用者使用的类。最终这个类通过自动配置类,将其添加进容器中,供使用者使用。
编写自动配置类:
@Configuration
@ConditionalOnWebApplication // web应用才能够生效
@EnableConfigurationProperties(HelloProperties.class) // 使属性文件生效
public class HelloServiceAutoConfiguration {
@Autowired
HelloProperties helloProperties;
// 将service注入到容器中,共我们使用
@Bean
public HelloService helloService() {
HelloService service = new HelloService();
service.setHelloProperties(helloProperties);
return service;
}
}
至此,我们编写了一个简单的starter
。其作用,就是在页面中返回HelloService
中的以下这个函数的返回值:
public String sayHello(String name) {
return helloProperties.getPrefix() + "-" + name + helloProperties.getSuffix();
}
最后,分别将selfdef-spring-boot-starter
、selfdef-spring-boot-starter-autoconfigurer
通过Maven
中的install
,将其打包进Maven
仓库供我们使用依赖。
注意:因为,selfdef-spring-boot-starter
中引入了selfdef-spring-boot-starter-autoconfigurer
,供在打包时,先打包后者,再打包前者。
三、测试
创建一个新的web
工程的Springboot
项目,在其pom.xml
文件中,引入上面我们自定义的selfdef-spring-boot-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.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.chemlez</groupId>
<artifactId>spring-boot-starter-09</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-starter-09</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-starter-web</artifactId>
</dependency>
<!-- 当前依赖就是我们前面自定义的starter -->
<dependency>
<groupId>cn.chemlez</groupId>
<artifactId>seldef-springboot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
编写控制器类:
@Controller
public class HelloController {
@Autowired
private HelloService helloService;
@RequestMapping("/hello")
@ResponseBody
public String hello() {
String hello = helloService.sayHello("Tom");
return hello;
}
}
配置文件的编写。因为我们在第二节中的配置类中,设定了前缀(prefix
)和后缀(suffix
)。因此,要在配置文件中,将其配置出。
chemlez.hello:
prefix: 张三
suffix: 李四
启动Springboot
项目,访问8080
端口下的hello
。结果:
张三-Tom李四