Starter是什么 ?
Spring Boot 对比 Spring MVC 最大的优点就是使用简单,约定大于配置。不用 Spring MVC 的时候,时不时被 xml 配置文件搞的晕头转向,冷不防还因为 xml 配置上的一点疏忽,导致整个项目莫名其妙的不可用,顿感生无可恋。这要归功于Spring Boot 的各种各样的 starters,有官方提供以及第三方开源出来的。这些依赖模块都遵循着约定成俗的默认配置,并允许我们根据自身情况调整这些配置。基本上你打算用的功能都可以找到,如果没有找到,那就请再找一找。SpringBoot 会自动扫描需要加载的信息并启动相应的默认配置。
Starter 提供了以下功能:
- 整合了模块需要的所有依赖,统一集合到 Starter 中。
- 提供了默认配置,并允许我们调整这些默认配置。
- 提供了自动配置类对模块内的 Bean 进行自动装配,注入 Spring 容器中。
Starter 命名规则
Spring 官方定义的 Starter 通常命名遵循的格式为 spring-boot-starter-{name},例如 spring-boot-starter-data-mongodb。Spring 官方建议,非官方 Starter 命名应遵循 {name}-spring-boot-starter 的格式,例如,myjson-spring-boot-starter。
Starter可以用来解决什么问题?
日常开发中有一些独立于业务系统之外的配置模块,它是可以在不同项目中进行复用的。如果在每个项目中都编写重复的模块代码,除了浪费时间和人力耦合性还高。将这些可独立于业务代码之外的功能配置模块封装成一个 Starter,在需要用到此功能模块的项目中,只需要在其 pom.xml 文件中引用依赖即可。
手写SpringBoot启动器的主要步骤
- 定义业务接口、需要的实体类等业务对象
- 定义配置属性类、
- 定义自动装配类、
- Resources目录下新建META-INF/spring.factories,加入自定义starter的配置项
- idea——new project——spring initializr——填写group、artifact名称,选择java的jdk版本——next ——next——finish
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.4.4</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>my-starter</artifactId> <version>0.0.1-SNAPSHOT</version> <name>my-starter</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>com.example</groupId> <artifactId>myjson-spring-boot-starter-autoconfigurer</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
</project> |
- 在当前工程创建module——name为myjson,流程同上
<?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.4</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>myjson-spring-boot-starter-autoconfigurer</artifactId> <version>0.0.1-SNAPSHOT</version> <name>myjson-spring-boot-starter-autoconfigurer</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</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <version>2.3.8.RELEASE</version> <optional>true</optional> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.73</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>2.3.8.RELEASE</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> <configuration> <mainClass>com.example.myjson.MyjsonApplication</mainClass> <skip>true</skip> </configuration> </plugin> </plugins> </build>
</project> |
加红色的三个依赖,fastjson是我们需要的第三方依赖,其他的spring-boot-configuration-processor 依赖是可选的,加入此依赖主要是打包时,自动生成配置元信息文件 META-INF/spring-configuration-metadata.json,并放入到 jar 中。绿色的artifact是我们自定义starter的名称,蓝色的插件依赖是我们
- 手写starter
- 定义我们的service业务类:主要是对传入的对象转换为json字符串,同时在其首位做额外的拼接处理
public class MyJsonService { private String prefixName; private String suffixName;
public String getPrefixName() { return prefixName; }
public void setPrefixName(String prefixName) { this.prefixName = prefixName; }
public String getSuffixName() { return suffixName; }
public void setSuffixName(String suffixName) { this.suffixName = suffixName; }
public String objectToMyJson(Object obj) { return prefixName + JSON.toJSONString(obj) + suffixName; } } |
- 定义控制的实体类对象
public class Person { private String name; private int age; private String address; public Person(String name, int age, String address) { super(); this.name = name; this.age = age; this.address = address; }
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; }
public String getAddress() { return address; }
public void setAddress(String address) { this.address = address; } } |
- 定义我们的属性配置类(也即yml配置文件中配置的属性)
/** * @author:cp * @time:2021-4-12 * @Description: 配置类(类名一般为模块名+Properties) cp.json为Starter使用者通过yml配置文件动态修改属性值的变量名前缀 */ @ConfigurationProperties(prefix = "cp.json") public class MyJsonProperties { // Starter使用者没在配置文件中配置prefixName属性的值时的默认值 public static final String DEFAULT_PREFIX_NAME = "@";
// Starter使用者没在配置文件中配置suffixName属性的值时的默认值 public static final String DEFAULT_SUFFIX_NAME = "#"; private String prefixName = DEFAULT_PREFIX_NAME; private String suffixName = DEFAULT_SUFFIX_NAME;
public String getPrefixName() { return prefixName; }
public void setPrefixName(String prefixName) { this.prefixName = prefixName; }
public String getSuffixName() { return suffixName; }
public void setSuffixName(String suffixName) { this.suffixName = suffixName; } } |
- 定义自动装配类,让spring装配我们的service业务类,同时调用我们的属性配置类,让业务service类获取到属性配置类的值并进行处理
package com.example.myjson.config;
import com.example.myjson.service.MyJsonService; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
/** * @author:cp * @time:2021-4-12 * @Description: 自动装配类 */ @Configuration @ConditionalOnClass(MyJsonService.class) // 表示只有指定的class在classpath上时才能被注册 @EnableConfigurationProperties(MyJsonProperties.class) // 激活被@ConfigurationProperties注解修饰的类 public class MyJsonConfiguration { private MyJsonProperties myJsonProperties;
// 自动注入配置类 public MyJsonConfiguration(MyJsonProperties myJsonProperties) { this.myJsonProperties = myJsonProperties; }
// 创建MyJsonService对象,注入到Spring容器中 @Bean @ConditionalOnMissingBean(MyJsonService.class) // 当容器没有此bean时,才注册 public MyJsonService myJsonService() { MyJsonService myJsonService = new MyJsonService(); myJsonService.setPrefixName(myJsonProperties.getPrefixName()); myJsonService.setSuffixName(myJsonProperties.getSuffixName()); return myJsonService; } } |
- 在我们的启动类模块的resources文件下创建META-INF/spring.factories 文件,增加如下内容,将自动装配的类配置上
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.myjson.config.MyJsonConfiguration |
- 上述工作完成后,我们可以使用mvn install命令在本地仓库生成我们手写的starter的jar,可以提供给他其他工程依赖引用。也可以快捷的使用idea提供的快捷打包
- 新建一个工程,名称为kk,流程同(1)中,在pom文件中引入我们的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.4</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>kk</artifactId> <version>0.0.1-SNAPSHOT</version> <name>kk</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> <dependency> <groupId>com.example</groupId> <artifactId>myjson-spring-boot-starter-autoconfigurer</artifactId> <version>0.0.1-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> |
- 更新maven依赖后,可以看我们的自定义starter已经被引入进来,在kk工程的resources文件下将application.properties文件改为application.yml并进行如下配置
cp: json: prefix-name: hello suffix-name: world |
- 在kkApplication下新建controller
@RestController @RequestMapping("demo") public class DemoController { @Autowired private MyJsonService myJsonService;
@GetMapping() public String test() { Person p = new Person(“千与千寻” , 18, "拉斯维加斯"); // 调用服务方法 return myJsonService.objectToMyJson(p); } } |
引入我们自定义启动器中的业务service类,启动springboot工程,访问http://localhost:8080/demo,验证我们的service类即可。
中间问题点:在打包自定义启动器类jar包本地仓库时,没有添加构建插件,导致生成包多了一个BOOT-INF的文件,无法被其他工程引用导入自定义service类:添加如下构建插件后问题解决:
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>com.example.myjson.MyjsonApplication</mainClass> <skip>true</skip> </configuration> </plugin> </plugins> </build> |