Spring Boot 自定义 Starter

前面的代码中,无论是 Spring Boot 中使用 Web、Test,还是 MyBatis、Dubbo,都是通过导入一个相应的 Starter 依赖,然后由 Spring Boot 自动配置完成的。那么,如果我们自己的某项功能也想通过自动配置的方式应用到 Spring Boot 中,为 Spring Boot 项目提供相应支持,需要怎样实现呢?同样,我们需要定义自己的 Starter。

1. 手写 Starter

1.1 需求

下面我们自定义一个我们自己的 Starter,实现的功能是:为用户提供的字符串添加前辍与后辍,而前辍与后辍定义在 yml 或 properties 配置文件中。例如,用户输入的字符串为 China,application.yml 配置文件中配置的前辍为$$$,后辍为+++,则最终生成的字符串为$$$China+++

1.2 实现

A、创建工程

创建一个 Spring Boot 工程,命名为 wrap-spring-boot-starter,并导入 Configuration Processor 与 Lombok 依赖。

Spring Boot 官方给出的 Starter 工程的命名需要遵循如下规范

  • Spring 官方定义的 Starter 格式为:spring-boot-starter-{name},如 spring-boot-starter-web。
  • 非官方 Starter 命名格式为:{name}-spring-boot-starter,如 dubbo-spring-boot-starter。

spring boot properties 自定义_spring boot

spring boot properties 自定义_自定义_02

导入的配置处理器依赖为:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-configuration-processor</artifactId>
	<optional>true</optional>
</dependency>

配置以后,在用@ConfigurationProperties的时候,如果配置类写好了成员属性,在配置文件里面会有友好提示。

B、 定义一个 Service 类

该 Service 类是当前 Starter 功能的核心类。其核心功能就是在这个类中完成的。该类中的成员变量可以随意命名,但一般与欲在 Spring Boot 中使用的属性名同名。

@AllArgsConstructor
public class WrapService {
    private String before;
    private String after;

    // 核心业务方法
    public String wrap(String word) {
        return before + word + after;
    }
}

C、 定义配置属性封装类

我们指定当前类用于封装来自于 Spring Boot 核心配置文件中的以 wrap.service 开头的 prefix 与 suffix 属性值。即用于封装配置文件中的如下属性值:

  • wrap.service.prefix
  • wrap.service.suffix

该类的对象是由系统自动创建,所以无需将其将给 Spring 容器管理。

// 要读取配置文件中wrap.service.prefix  与  wrap.service.suffix 两个属性的值
@Data
@ConfigurationProperties("wrap.service")
public class WrapServiceProperties {
    private String prefix;
    private String suffix;
}

D、定义自动配置类

为了加深对“自动配置类与配置文件属性关系”的理解,这里再增加一个功能:为wrap.service 再增加一个组装开关,一个 boolean 属性 enable,当 enable 属性值为 true 时,或没有设置 some.service.enable 属性时才进行组装,若 enable 为 false,则不进行组装。

/**
 * 所谓自动配置,就是配置核心业务实例,或者说,是创建核心业务实例
 */
@Configuration
@ConditionalOnClass(WrapService.class)
@EnableConfigurationProperties(WrapServiceProperties.class)
public class WrapServiceAutoConfiguration {
    @Autowired
    private WrapServiceProperties properties;

    @Bean
    @ConditionalOnProperty(name = "wrap.service.enable", havingValue = "true", matchIfMissing = true)
    // havingValue = "true" 表示如果wrap.service.enable值为true则条件成立
    // 如果没有配havingValue的值,那么只要值不为"false",都认为条件成立!
    // matchIfMissing 表示如果没有对应配置,那么默认是条件成立还是不成立
    public WrapService wrapService() {
        return new WrapService(properties.getPrefix(), properties.getSuffix());
    }
	
	// 注意在@Configuration的类中@Bean的创建是有顺序的
	// 下面这个放到上面那么容器中就会有两个WrapService 实例
    @Bean
    @ConditionalOnMissingBean  //容器中没有实例才会创建
    public WrapService wrapService2() {
        return new WrapService("", "");
    }
}

E、 创建 spring.factories 文件

在 resources/META-INF 目录下创建一个名为 spring.factories 的文件。该配置文件是一个键值对文件,键是固定的,为 EnableAutoConfiguration 类的全限定性类名,而值则为我们自定义的自动配置类。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.abc.config.WrapServiceAutoConfiguration

2. 使用自定义的 Starter

在本地要使用我们自定义的 Starter,首先要保证其已经被 Install 到了本地 Maven 库。

(1) 创建工程

创建一个 Spring Boot 工程,仅需要一个 web 依赖。

spring boot properties 自定义_spring boot_03

(2) 导入自定义 Starter 依赖

<dependency>
    <groupId>com.abc</groupId>
    <artifactId>wraper-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

(3) 定义 properties.yml
自定义 Starter 中的属性在配置文件中也是有自动提示功能的。

wrap:
  service:
    enable: true   # 开关
    prefix: AAA-
    suffix: -BBB

(4) 定义 Controller

@RestController
public class WrapController {
    @Autowired
    private WrapService service;

    @RequestMapping("/wrap/{param}")
    public String wrapHandler(@PathVariable("param") String param) {
        return service.wrap(param);
    }
}

(5) 运行访问

启动类无需修改,直接启动运行即可。

spring boot properties 自定义_自定义_04