why?
纯属个人缘由。是因为项目开发过程中依赖了各种官方starter
,很好奇为什么引入后,其所携带的功能,项目中可以随意使用,而且可添加配置实现个性化、可不添加走默认。
带着好奇直接面向百度,就从好几篇文章中学到了核心思想。
简介boot-starter
boot-starter是boot项目的一个亮点,可降低项目开发中复杂代码量,且节省大量配置,非常符合约定大于配置
思想,是一个开箱即用的好组件,在我看来,核心思想也为封装,没什么是封装
解决不了的问题,封装大量工具,且提供各式各样的模式选择,使用者只需加点配置即可完美嵌入。
实现原理
相信大家也百度过为啥@SpringBootApplication
一个注解这么牛啤,它其中实际上代替了三个注解:@SpringBootConfiguration
标记启动类为配置类、@ComponentScan
注册启动类同级及子包下的所有bean、@EnableAutoConfiguration
自动装配。因此核心就是@EnableAutoConfiguration
底层读取spring.factories
配置组件的全类名,给IOC容器完成bean注册。
上面提到了spring.factories
,该文件就是为了解决jar包中的类加载到容器中的,SpringBoot在SpringFactoriesLoader类中,以硬编码的方式指定了spring.factories
这个路径,所以这个文件就是一个扩展点。
说到这里就不得不提Java-Spi机制
了。SPI全程Service Provider Interface。为某个接口寻找服务实现。类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。项目中多处有SPI机制的影子,可具体参考文末文章中讲解。
注解学习
//spring工程是否引入了该类 ↓
@ConditionalOnClass
// 配置属性给类↓
@ConfigurationProperties
// 使得@ConfigurationProperties类生效(bean) ↓
@EnableConfigurationProperties
// 保证该bean只有一个 ↓
@ConditionalOnMissingBean
// 当表达式为true的时候,才会实例化这个bean ↓
@ConditionalOnExpression
// 根据属性值决定加不加载 ↓
@ConditionalOnProperty
代码实战
演示说明
该项目仅仅是为了演示新建一个自己的boot-stater,通过自己项目配置可个性化boot-starter的功能,实际上它也广泛应用于-通过配置-为一个接口找到其实现类。
本项目演示:新建一个myjson-spring-boot-stater
为了给json序列化成字符串后,加上指定前后缀字符,纯纯演示项目,没有任何实际价值。
注意命名规范:
Spring官方命名:spring-boot-starter-{name}
建议非官方:{name}-spring-boot-starter
实际代码
- 新建工程-Pom:
// 新建一个maven工程 myjson-spring-boot-stater`
<dependencies>
<!-- 自动生成配置元信息文件 -->
<!-- 其他项目引入该jar后,会自动生成配置文件说明 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<!-- fastJson -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.1</version>
</dependency>
</dependencies>
- 创建业务类MyJsonService
@Data
public class MyJsonService {
// 前缀
private String prefixName;
// 后缀
private String suffixName;
/**
* 将对象json序列号, 并加上前后缀
*/
public String objectToMyJson(Object o) {
return prefixName + JSON.toJSONString(o) + suffixName;
}
}
- 创建配置属性类MyJsonProperties
@Data
@ConfigurationProperties(prefix = "config.json")
public class MyJsonProperties {
// Starter使用者没在配置文件中配置prefixName属性的值时的默认值
public static final String DEFAULT_PREFIX_NAME = "Default prefix";
// Starter使用者没在配置文件中配置suffixName属性的值时的默认值
public static final String DEFAULT_SUFFIX_NAME = "Default suffix";
private String prefixName = DEFAULT_PREFIX_NAME;
private String suffixName = DEFAULT_SUFFIX_NAME;
}
- 创建核心配置类MyJsonConfiguration
@Configuration
@ConditionalOnClass(MyJsonService.class)
@EnableConfigurationProperties(MyJsonProperties.class)
public class MyJsonConfiguration {
@Resource
private MyJsonProperties myJsonProperties;
@Bean
@ConditionalOnProperty(name = "config.json.enable", matchIfMissing = true)
@ConditionalOnMissingBean(MyJsonService.class)
public MyJsonService myJsonService() {
MyJsonService myJsonService = new MyJsonService();
myJsonService.setPrefixName(myJsonProperties.getPrefixName());
myJsonService.setSuffixName(myJsonProperties.getSuffixName());
return myJsonService;
}
}
- 核心-资源resource目录下新建META-INF目录,然后新建spring.factories文件,指定全路径,暴露给项目注册Bean
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
siri.hlb.config.MyJsonConfiguration
- 自己项目依赖该jar包, 并添加yml配置
cofig:
json:
prefixName: modified-prefix
suffixName: modified-suffix
enable: true
- 业务中即可直注入使用即可
@Resource
private MyJsonService myJsonService;// 注入
// 直接调用
myJsonService.objectToMyJson(new Object());
学习文章参考:
1. 手写一个boot starter
2. Java中SPI机制
3. springboot自动装配原理