starter基本概念
我们再回顾下starter的概念:starter 是 SpringBoot 中一种非常重要的机制,它可以繁杂的配置统一集成到 starter 中,我们只需要通过 maven 将 starter 依赖引入到项目中,SpringBoot 就能自动扫描并加载相应的默认配置。starter 的出现让开发人员从繁琐的框架配置中解放出来,将更多的精力专注于业务逻辑的开发,极大的提高了开发效率。在一些特殊情况下,我们也可以将一些通用功能封装成自定义的 starter 进行使用。
命名规范
SpringBoot 提供的 starter 以 spring-boot-starter-xxx 的形式命名。为了与 SpringBoot 生态提供的 starter 进行区分,官方建议第三方开发者或技术(例如 Druid、Mybatis 等等)厂商自定义的 starter 使用 xxx-spring-boot-starter 的形式命名,例如 mybatis-spring-boot-starter、druid-spring-boot-starter 等等
模块规范
Spring Boot 官方建议我们在自定义 starter 时,创建两个 Module :autoConfigure Module 和 starter Module,其中 starter Module 依赖于 autoConfigure Module。当然,这只是 Spring Boot 官方的建议,并不是硬性规定,若不需要自动配置代码和依赖项目分离,我们也可以将它们组合到同一个 Module 里
自定义starter步骤
自定义 starter 可以分为以下 7 步:创建工程—》添加 POM 依赖—》定义 propertie 类—》定义 Service 类–》定义自动配置类—》创建 spring.factories文件—》构建 starter,接下来我们按照步骤实现一遍
1 创建工程
在IDEA中新建一个空项目
填写项目信息: tml-spring-boot-starter
创建第一个模块:tml-spring-boot-starter
创建第二个模块:tml-spring-boot-starter-autoconfiguration
两个模块都按照如下选项创建:
两个模块选择好后如下:
创建完后项目界面如下:
2 添加 POM 依赖
在tml-spring-boot-starter的 pom.xml 中添加以下代码,将tml-spring-boot-starter-autoconfiguration 作为其依赖项
<!--添加自动配置模块为其依赖-->
<dependency>
<groupId>com.example</groupId>
<artifactId>tml-spring-boot-starter-autoconfiguration</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
3 定义 propertie 类
在tml-spring-boot-starter-autoconfiguration 的properties 包中,创建一个实体类:PersonProperties,通过它来映射配置信息
package com.example.tmlspringbootstarterautoconfiguration.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
/**
* 实体类,用来映射配置信息
*/
@Data
@ConfigurationProperties(prefix = "person")
@PropertySource(value = "classpath:application.properties")
public class PersonProperties {
private String prefix;
private String suffix;
}
4 定义 Service 类
在tml-spring-boot-starter-autoconfiguration 的 services包中,创建一个 Service 类:PersonService,供其他项目使用
package com.example.tmlspringbootstarterautoconfiguration.services;
import com.example.tmlspringbootstarterautoconfiguration.properties.PersonProperties;
import javax.annotation.Resource;
public class PersonService {
@Resource
PersonProperties personProperties;
public String sayHello(String userName) {
return personProperties.getPrefix() + userName + personProperties.getSuffix();
}
}
5 定义自动配置类
在tml-spring-boot-starter-autoconfiguration的autoConfiguration包 中,创建一个配置类:PersonAutoConfiguration,其代码如下
package com.example.tmlspringbootstarterautoconfiguration.autoConfiguration;
import com.example.tmlspringbootstarterautoconfiguration.properties.PersonProperties;
import com.example.tmlspringbootstarterautoconfiguration.services.PersonService;
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;
@Configuration
@EnableConfigurationProperties(PersonProperties.class) //启用 PersonProperties,并默认将它添加到容器中
public class PersonAutoConfiguration{
@ConditionalOnMissingBean(PersonService.class) //当容器中没有 PersonService 时生效
@Bean
public PersonService personService() {
PersonService personService = new PersonService();
return personService ;
}
}
PersonAutoConfiguration使用了以下 4 个注解:
@Configuration:表示该类是一个配置类;
@EnableConfigurationProperties(HelloProperties.class):该注解的作用是为 HelloProperties 开启属性配置功能,并将这个类以组件的形式注入到容器中;
@ConditionalOnMissingBean(HelloService.class):该注解表示当容器中没有 HelloService 类时,该方法才生效;
@Bean:该注解用于将方法的返回值以 Bean 对象的形式添加到容器中。
这样自动配置类就将组件和配置绑定并且都注入到容器中了。
6 创建 spring.factories文件
由于 Spring Boot 的自动配置是基于 Spring Factories 机制实现的,因此我们自定义 starter 时,同样需要在项目类路径下创建一个 spring.factories 文件。在tml-spring-boot-starter-autoconfiguration 的类路径下(resources )中创建一个 META-INF 文件夹,并在 META-INF 文件夹中创建一个 spring.factories 文件
将 Spring Boot 的 EnableAutoConfiguration 接口与自定义 starter 的自动配置类 PersonAutoConfiguration组成一组键值对添加到 spring.factories 文件中,以方便 Spring Boot 在启动时,获取到自定义 starter 的自动配置,代码如下
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.tmlspringbootstarterautoconfiguration.autoConfiguration.PersonAutoConfiguration
7 构建 starter
接下来,我们需要对自定义 starter 进行构建,并将它安装到本地仓库或远程仓库中,供其他项目使用。由于我们是在本地的项目中引用和测试,因此只需要使用 install 命令安装到本地仓库即可,因为存在依赖关系,所以先构建tml-spring-boot-starter-autoconfiguration再构建tml-spring-boot-starter
构建过程中遇到一些问题,只要在pom中的build按照如下内容配置即可避免:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${project.parent.version}</version>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<!--添加配置跳过测试-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<!--添加配置跳过测试-->
</plugins>
</build>
使用自定义starter
我们来测试下自定义的starter
1 新建测试项目
新建一个Moudle来使用我们的自定义starter
在其 pom.xml 中引入依赖tml-spring-boot-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.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>test-springboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>test-springboot</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--引入自定义 starter -->
<dependency>
<groupId>com.example</groupId>
<artifactId>tml-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</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>
2 编写配置文件
在 Spring Boot 配置文件 application.yml中,添加以下属性配置
#自定义 starter prefix 属性
person:
prefix: 兄弟
#自定义 starter suffix 属性
suffix: 欢迎一起玩儿SpringBoot!
3 创建测试控制器
在 controller包 中创建一个控制器类 PersonController
package com.example.testspringboot.controller;
import com.example.tmlspringbootstarterautoconfiguration.services.PersonService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
@Controller
public class PersonController {
//自动装配自定义 starter 的 service
@Resource
PersonService personService;
@ResponseBody
@GetMapping("/personInfo")
public String SayHello(String name) {
return personService.sayHello(name);
}
}
请求后结果如下,可以看到配置也被读取出来了
总结一下
其实实现一个自定义starter的过程就是把前面所有SpringBoot相关内容复习一遍的过程,通过SpringBoot自动配置,我们初始化好了自动配置类,把组件和配置信息绑定并注入到容器中,然后将这个场景启动器提供出来,供外边的第三方使用,我们成了一个starter的服务提供商,我觉得这样实现一遍后对SpringBoot的实现理解的更加透彻了。