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 山茶花读不懂白玫瑰 人海遇见人海归