什么是starter
Starter相当于模块,它能将模块所需的依赖整合起来并对模块内的Bean根据环境(条件)进行自动配置。
使用者只需要依赖相应功能的Starter,无需做过多的配置和依赖,Spring Boot就能自动扫描并加载相应的模块并设置默认值,做到开箱即用
什么时候需要封装成starter,即场景
1)有复用价值,并有动态配置的配置项(提供默认配置)需要开放给使用者配置,或者项目中的类需要注册到spring的单例池中,
提供给服务直接@Autowread注入,方便对模块内的 Bean 进行自动装配,开箱即用
2)一些模块、框架的集成,例如与Redis、Mybatis等框架,需要与spring进行深度集成的,抽象出starter,引入依赖,开箱即用
3)通过封装成starter,可以将多个相关的依赖打包为一个单独的依赖项,简化项目的依赖管理和版本控制,减少开发者的工作量。
4)封装多个功能,提供统一的服务层,将其封装成一个starter,提供统一的接口和抽象层
5)公司内部模块服务,封装提供集成,开箱即用,例如:鉴权、邮件、短信、验证码等
命名约定
1)spring官方封装的starter:spring-boot-starter-{服务名}
例如:spring-boot-starter-data-redis
2)自己开发的starter:{服务名}-spring-boot-starter
例如:mybatis-spring-boot-starter
spring.factories
Spring Boot会默认扫描跟启动类平级的包,如果我们的Starter跟启动类不在同一个主包下, 需要通过配置spring.factories文件来配置生效,SpringBoot默认加载各个jar包下classpath路径的spring.factories文件, 配置的key为org.springframework.boot.autoconfigure.EnableAutoConfiguration
Starter开发常用注解
属性映射注解
- @ConfigurationProperties :配置文件属性值和实体类的映射
- @EnableConfigurationProperties:和@ConfigurationProperties配合使用,把@ConfigurationProperties修饰的类加入ioc容器。
配置bean注解
- @Configuration :标识该类为配置类,并把该类注入ioc容器
- @Bean :一般在方法上使用,声明一个bean,bean名称默认是方法名称,类型为返回值。
条件注解
- @Conditional:是根据条件类创建特定的Bean,条件类需要实现Condition接口,并重写matches接口来构造判断条件。
- @ConditionalOnBean :容器中存在指定bean,才会实例化一个Bean
- @ConditionalOnMissingBean:容器中不存在指定bean,才会实例化一个Bean
- @ConditionalOnClass:系统中有指定类,才会实例化一个Bean
- @ConditionalOnMissingClass:系统中没有指定类,才会实例化一个Bean
- @ConditionalOnExpression:当SpEl表达式为true的时候,才会实例化一个Bean
- @AutoConfigureAfter :在某个bean完成自动配置后实例化这个bean
- @AutoConfigureBefore :在某个bean完成自动配置前实例化这个bean
- @ConditionalOnJava :系统中版本是否符合要求
- @ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者有多个但是指定了首选的Bean时触发实例化
- @ConditionalOnResource:类路径下是否存在指定资源文件
- @ConditionalOnWebApplication:是web应用
- @ConditionalOnNotWebApplication:不是web应用
- @ConditionalOnJndi:JNDI指定存在项
- @ConditionalOnProperty: 配置Configuration的加载规则
- prefix :配置属性名称的前缀
- value :数组,获取对应property名称的值,与name不可同时使用
- name :数组,可与prefix组合使用,组成完整的配置属性名称,与value不可同时使用
- havingValue :比较获取到的属性值与havingValue给定的值是否相同,相同才加载配置
- matchIfMissing :缺少该配置属性时是否可以加载。如果为true,没有该配置属性时也会正常加载;反之则不会生效
开发Starter
1)创建项目,命名xxx-spring-boot-starter
2)pom.xml中maven打包插件spring-boot-maven-plugin,因为没有main入口
3) 编写属性类
@ConfigurationProperties可以定义一个配置信息类,和配置文件进行映射
@ConfigurationProperties(prefix = "ljw.config")
public class HelloProperties {
private String name = "hello 默认值!";
private int age = 8;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
4)编写自动配置类
命名规范:XxxAutoConfiguration
@Configuration(proxyBeanMethods = false)
// 当存在某个类时,此自动配置类才会生效
@ConditionalOnClass(value = {HelloService.class})
// 导入我们自定义的配置类,供当前类使用
@EnableConfigurationProperties(value = HelloProperties.class)
// 只有非web应用程序时此自动配置类才会生效
@ConditionalOnWebApplication
//判断ljw.config.flag的值是否为“true”, matchIfMissing = true:没有该配置属性时也会正常加载
@ConditionalOnProperty(prefix = "ljw.config", name = "flag", havingValue = "true", matchIfMissing = true)
public class HelloAutoConfiguration {
/**
* @param helloProperties 直接方法签名入参注入HelloProperties,也可以使用属性注入
* @return
*/
@Bean
@ConditionalOnMissingBean(HelloService.class)
//@ConditionalOnProperty(prefix = "ljw.config", name = "flag", havingValue = "true", matchIfMissing = true)
public HelloService helloService(HelloProperties helloProperties) {
HelloService helloService = new HelloService();
//把获取的信息注入
helloService.setName(helloProperties.getName());
helloService.setAge(helloProperties.getAge());
return helloService;
}
}
5)编写spring.factories
把自动配置类HelloAutoConfiguration配置到org.springframework.boot.autoconfigure.EnableAutoConfiguration的key下,springboot会自动加载该文件并根据条件装配
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.ljw.starter.config.HelloAutoConfiguration