spring boot custom starter

spring boot starter 加载原理、相关注解、自定义 starter


1、spring boot 启动原理

  首先 spring boot 以 @SpringBootApplication 注解启动 spring boot 项目,启动时会通过两种方式来加载配置。

  • SpringApplication.run():通过该方法来加载通过 spring 方式配置的 bean(如注解、xml 等),然后将这些 bean 加载到 spring ioc 容器中。具体加载原理请戳 。
  • @EnableAutoConfiguration:通过该方法来加载项目中的 starter 依赖中配置的 bean,然后将这些 bean 加载到 spring 容器中,即自动装配。具体原理是:@EnableAutoConfiguration 注解存在于 @SpringBootApplication 注解,@EnableAutoConfiguration 注解中 import 了一个 AutoConfigurationImportSelector 加载器,该加载器回去项目所依赖的 jar 包下的 META-INF 目录下找 spring.factories 文件,该文件中配置了自动配置类的路径,若存在该文件,则按照配置信息去加载对应的自动配置累,从而达到自动装配的效果。自动配置类一般形如 XxxAutoConfiguration。

2、相关注解

  springboot还为我们提供了很多自动装配的注解,其都扩展自 spring 的 @Conditional 注解。

  • @ConditionalOnBean
    该注解的作用是仅当 spring 容器中存在指定的 bean 时才装配。可通过 bean 类型和 bean 名称进行指定,即 value 和 type 参数。
  • @ConditionalOnClass
    该注解的作用是仅当存在指定的类时才装配。可通过类路径(classpath)和类名称进行指定。即 value 和 name 的参数。
  • @ConditionalOnCloudPlatform
    该注解的作用是仅当指定的云平台处于活动状态时才装配。可通过 value 参数进行指定云平台。
  • @ConditionalOnExpression
    该注解的作用仅当指定的 spel 表达式返回 true 时才进行装配。可通过 value 参数进行指定 spel 表达式。
  • @ConditionalOnJava
    该注解的作用是仅当应用程序运行在指定的 jvm 版本上或运行在指定的 jvm 版本范围内时才进行装配。可通过 value 和 range 参数指定 jvm 版本或版本范围。
  • @ConditionalOnJndi
    该注解的作用是仅当指定位置的 Jndi 存在时或 InitialContext 存在时才进行装配。可通过 value 参数指定 Jndi 位置。
  • @ConditionalOnMissingBean
    该注解的作用是仅当 spring 容器没有指定的 bean 时才进行装配。可通过 bean 类型和 bean 名称进行指定,即 value / type(多个)和 name 参数。
  • @ConditionalOnMissingClass
    该注解的作用是仅当指定名称的类存在时才进行装配。可通过 value 参数指定类名称。
  • @ConditionalOnNotWebApplication
    该注解的作用是仅当当前应用上下文不是 web 应用上下文时才进行装配。
  • @ConditionalOnProperty
    该注解的作用是仅当指定的属性拥有指定值时才进行装配。默认情况下该属性必须存在于环境中。且不等于 false。还可以使用 havingValue 参数来指定属性值;当属性不存在于环境中时,可通过 matchIfMissing 参数指定重新匹配的属性名。另外,可通过 value、name 和 prefix 等参数来指定要匹配的属性名或前缀等。
  • @ConditionalOnResource
    该注解的作用是仅当指定的资源存在于 classpath 时才进行装配。可通过 resources 参数来指定资源。
  • @ConditionalOnSingleCandidate
    该注解的作用是仅当指定类的 bean 已经存在于 bean factory 中,且确定其是单例(如果在 bean factory 匹配到了多个 bean,但是有一个 primary(主要的)修饰的 bean 也适用)候选者时才进行装配。可通过 value 和 type 参数指定要检查的 bean 的类类型或类型名称,单二者不可同时使用。
  • @ConditionalOnWarDeployment
    该注解的作用是仅当当前应用是以传统的 war 包方式部署时才进行装配。但当该应用是嵌入式服务时则不适用。
  • @ConditionalOnWebApplication
    该注解的作用是仅当当前应用是 web 应用时才进行装配。默认情况下适用于所有 web 应用,可以通过 type 参数来指定 web 应用的范围,如所有 web 应用、基于 servlet 的 web 应用、响应式的 web 的应用等。

3、自定义 starter

  前面描述过 spring boot 记载 starter 的过程,所以自定义 starter 大致分为定义 starter 配置、功能实现、AutoConfiguration 自动装配以及 spring.factories 文件 这些步骤。

3.1、定义 starter 配置
// starter 属性配置 即对外提供的配置
@ConfigurationProperties(prefix = "demo.user")
public class DemoProperties {

    private String username;

    private String password;

    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}
3.2、功能实现
// 功能实现
public class DemoBean {

    private DemoProperties demoProperties;
  
    // 通过 @Autowired 注解注入配置
    @Autowired
    void setDemoProperties(DemoProperties demoProperties) {
        this.demoProperties = demoProperties;
    }

    // 模仿功能实现
    public String test(String message) {
        return demoProperties.getUsername() + " " + demoProperties.getPassword() + " " + message;
    }
}
3.3、AutoConfiguration
// 自动装配类
@Configuration   // 该必须通过该注解将该类标注为配置类 其余注解根据实际使用场景添加
@EnableConfigurationProperties(DemoProperties.class)   // 开启配置属性
public class DemoAutoConfiguration {

    // 注入 demoBean
    @Bean
    @ConditionalOnMissingBean
    public DemoBean demoBean() {
        return new DemoBean();
    }
}
3.4、spring.factories
# 开启自动配置参数 EnableAutoConfiguration 即表示自动装配
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
	# 参数值 即自动装配配置累的全路径 当有个多个配置累时用 ',\' 隔开 
  org.xgllhz.demo.auto.DemoAutoConfiguration
3.5、使用

  自定义 starter 开发完成后使用 maven 的 clean、install 命令将其安装到 maven 本地仓库,然后就可以在被需要的地方引入使用了。

  • 在 test 项目的 pom 文件中引入依赖
<dependency>
  <groupId>org.xgllhz</groupId>
  <artifactId>demo-starter</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>
  • 在 test 项目的 yml 文件中加入配置
demo:
  user:
    username: xgllhz
    password: you
  • 在测试类中测试
@RestController
@RequestMapping("/test")
@RequiredArgsConstructor
public class TestController {

    // 注入 starter 依赖中的 bean
    private final DemoBean demoBean;

    @PostMapping("/test")
    public String test() {
        return demoBean.test("山茶花读不懂白玫瑰 人海遇见人海归");
    }
}
  • 啥 你要看测试结果?(就一句话 有啥好看的)
xgllhz you 山茶花读不懂白玫瑰 人海遇见人海归