SpringBoot自定义Starter

346 阅读4分钟

描述

Spring Boot中的Starter是一种非常重要的机制,能够抛弃繁琐的配置,将其统一集成Starter自动装配组件,开发者只需要在maven中添加依赖即可。自动扫描需要加载的实例并启动相应的默认配置,Starter组件摆脱了各种依赖库的处理,需要配置各种信息的困扰。会自动通过classpath路径下的类发现需要的Bean,并注册到IOC容器。使用时,直接通过@Autowired注解调用。

自定义Starter的命名规则

SpringBoot提供的Starter以spring-boot-starter-xxxxx的方式命名

自定义的Start使用xxxxx-spring-boot-starter命名规则,以区分SpringBoot生态提供的Starter

依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
    <scope>provided</scope>
</dependency>

实现方案介绍

  • 方案一:加入starter依赖即可直接使用

  • 方案二:通过yml配置是否开启使用

  • 方案三:热拔插技术,通过注解是否开启

方案一

实体类Bean,可以通过yml或者properties配置修改默认数据

/**
 * Properties配置
 *
 * @author: 苦瓜不苦
 * @date: 2022/7/2 17:28
 **/
@Data
@ConfigurationProperties("account")
public class AccountProperties {

    /**
     * 用户名
     */
    private String username = "admin";

    /**
     * 密码
     */
    private String password = "admin";

}

配置类,提供方法

/**
 * @author: 苦瓜不苦
 * @date: 2022/7/2 17:26
 **/
@Slf4j
@Configuration
@EnableConfigurationProperties(AccountProperties.class)
public class SendMessageClient {

    private final AccountProperties accountProperties;

    public SendMessageClient(AccountProperties accountProperties) {
        this.accountProperties = accountProperties;
    }

    public void send(String content) {
        log.info("配置yml的数据 >>>>>> {}", JSON.toJSONString(accountProperties));
        log.info("方法传入的内容 >>>>>> {}", content);
    }

}

注入到IOC容器,在resource文件下创建META-INF/spring.factories。将配置类加载到IOC容器中,无需使用StringBootApplication启动类加载

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  org.example.SendMessageClient

配置Bean的注释,在resource文件下创建META-INF/spring-configuration-metadata.json。在yml修改配置时,会有注释提示。

{
  "properties": [
    {
      "name": "account.username",
      "type": "java.lang.String",
      "description": "用户名",
      "defaultValue": "admin"
    },
    {
      "name": "account.password",
      "type": "java.lang.String",
      "description": "密码",
      "defaultValue": "admin"
    }
  ]
}

方案二

其实和方案一的配置是一样的,只需要在SendMessageClient类上添加@ConditionalOnProperty(prefix = "account", name = "enable", havingValue = "true")注解就行

使用是在yml文件中通过account.enable=true开启,默认是不开启的。如果需要默认开启,则在@ConditionalOnProperty注解中添加matchIfMissing = true

@ConditionalOnProperty源码说明

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {

	// 数组,获取对应property名称的值,与name不可同时使用
	String[] value() default {};

	// 配置属性名称的前缀,比如spring.http.encoding
	String prefix() default "";

	// 数组,配置属性完整名称或部分名称
	// 可与prefix组合使用,组成完整的配置属性名称,与value不可同时使用
	String[] name() default {};

	// 可与name组合使用,比较获取到的属性值与havingValue给定的值是否相同,相同才加载配置
	String havingValue() default "";

	// 缺少该配置属性时是否可以加载。如果为true,没有该配置属性时也会正常加载;反之则不会生效
	boolean matchIfMissing() default false;

}

方案三

新增一个标记类

/**
 * 标记类
 *
 * @author: 苦瓜不苦
 * @date: 2022/7/2 19:09
 **/
public class AccountMarker {

}

热拔插注解

/**
 * 是否启动注解
 *
 * @author: 苦瓜不苦
 * @date: 2022/7/2 19:01
 **/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AccountMarker.class)
public @interface EnableAccount {
    
}

在SendMessageClient类上添加@ConditionalOnBean(AccountMarker.class)注解

上诉步骤配置完成之后,即可在项目中使用。只需要在SpringBoot的启动类上添加@EnableAccount注解则可以使用。

原理解析:通过开启@EnableAccount注解,@Import就会去加载AccountMarker类到IOC容器中,当SendMessageClient类上的@ConditionalOnBean注解就会判断出AccountMarker类在IOC容器中,然后对SendMessageClient类进行实例化操作,加载到IOC容器中。

扩展知识

注解解析
@ConditionalOnClass应用中包含某个类时,配置才生效
@ConditionalOnMissingClass应用中不包含某个类时,配置才生效
@ConditionalOnBeanSpring的IOC容器中存指定实例对象时,配置才生效
@ConditionalOnMissingBeanSpring的IOC容器中不存指定实例对象时,配置才生效
@ConditionalOnProperty指定参数的值符合要求时,配置才生效
@ConditionalOnResource指定文件资源存在时,配置才生效
@ConditionalOnWebApplication处于Web环境时(WebApplicationContext),配置才生效
@ConditionalOnNotWebApplication非处于Web环境时(WebApplicationContext),配置才生效
@ConditionalOnExpression指定参数的值符合要求是,配置才生效(和ConditionlOnProperty的区别可以使用springEL表达式)
@AutoConfigureAfter指定Configure类之后加载
@AutoConfigureBefore指定Configure类之前加载
@AutoConfigureOrder指定Configure类的加载顺序,默认0