自定义starter的应用场景、作用
宏观思想
- 自定义starter的主要功能是自动帮我们将某个JavaBean转换成SpringBean
- springboot或者其他第三方所提供的starter,都是做框架集成,通过简化配置,提高开发效率
- 开发工作中,有些框架是多个服务共用的,并且springboot或者其他第三方暂未提供,可以通过编写自定义starter来简化工作。
场景举例
邮件、短信、验证码等功能,经常是写在common包里。将这些功能封装成starter,可以避免common包的臃肿。
使用starter的好处
Springboot的出现极大的简化了开发人员的配置,而这之中的一大利器便是springboot的starter,starter是springboot的核心组成部分。starter帮助开发者们从繁琐的框架配置中解放出来,从而更专注于业务代码。
自定义starter说明
SpringBoot官方说明
在springboot官方文档中特别提到:我们需要创建两个module ,其中一个是autoconfigure module 一个是starter module ,其中 starter module 依赖 autoconfigure module。如果不需要将自动配置代码和依赖项管理分离开来,则可以将它们组合到一个模块中
命名规范
- springboot官方推出的starter 以spring-boot-starter-xxx的格式来命名
- 第三方开发者自定义的starter则以xxxx-spring-boot-starter的规则来命名
- 不按以上命名也没什么影响,只是显得野狐禅
自定义starter实现步骤
新建maven工程,添加依赖
<-- 包含核心启动器(spring-core)、包含自动配置(spring-boot-autoconfigure) -->
<-- 包含日志(spring-boot-starter-logging)、包含yaml(snakeyaml) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
定义Properties类
properties类主要作用是将 application.yaml 或 application.properties 中的配置信息映射成实体类,比如指定@ConfigurationProperties(prefix ="loard.custom"),就能取到以loard.custom为前缀的配置项。如果不需要取配置就不用写Properties类
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix ="loard.custom")
public class MyProperties {
private boolean enable;
private int max = 100;
private String url;
}
定义服务类XxxService,交由Spring管理的Bean
自定义starter的业务逻辑,真正使用Properties配置的地方。
服务类可以注入Properties使用其属性,也可在自定义的自动配置类里面设值。
@Slf4j
public class MyStarterService {
@Autowired
private MyStarterProperties properties;
public void business(){
if(properties.isEnable()){
log.info(properties.getUrl());
}
}
}
定义自动配置类XxxxAutoConfiguration.java
先看代码
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(MyStarterProperties.class)
@ConditionalOnProperty(prefix = "loard.custom", name = "enable", matchIfMissing = true)
public class MyStarterAutoConfiguration {
@Bean
@ConditionalOnMissingBean(MyStarterService.class)
public MyStarterService myStarterService(){
return new MyStarterService();
}
}
- @Configuration:表示该类是一个配置类;
- @EnableConfigurationProperties(xxxProperties.class):该注解的作用是为 xxxProperties 开启属性配置功能,并将这个类以组件的形式注入到容器中;
- @ConditionalOnProperty(prefix = "xxx", name= "x", matchIfMissing = true) : 当指定的配置项等于你想要的时候,配置类生效;
- @ConditionalOnMissingBean(xxx.class):该注解表示当容器中没有 xxx 类时,该方法才生效;
- @Bean:该注解用于将方法的返回值以 Bean 对象的形式添加到容器中。 当服务类(XxxService)没有直接注入Properties使用时,可以在AutoConfiguration类的构造器里注入Properties,然后在myStarterService方法给MyStarterService设值
@Conditional条件注解
@Condition可以做到满足条件时才注入bean。在有些时候我们准备了很多bean在不同的情况下使用,全注入进去也可,但是浪费资源。
Condition中获取application.properties的配置项:
String port = context.getEnvironment().getProperty("server.port");
Spring提供的Condition
- @ConditionalOnBean:仅仅在当前上下文中存在某个对象时,才会实例化一个Bean。
- @ConditionalOnClass:某个class位于类路径上,才会实例化一个Bean
- @ConditionalOnExpression:当表达式为true的时候,才会实例化一个Bean。
- @ConditionalOnMissingBean:仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean
- @ConditionalOnMissingClass:某个class类路径上不存在的时候,才会实例化一个Bean
- @ConditionalOnNotWebApplication:不是web应用
自定义Condition
当Spring提供的Condition满足不了需求时,可以自定义:
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//条件逻辑,返回true代表可以注入,false反之
return true;
}
}
使用自定义Condition:
@Configuration
public class MyStarterAutoConfiguration {
@Bean
//当Conditional中的matches方法返回true的时候 注入
@Conditional(MyCondition.class)
public MyStarterService myStarterService(){
return new MyStarterService();
}
}
创建spring.factories
在resources/META-INF/下创建spring.factories文件。把自定义的XxxxAutoConfiguration添加进去:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.xxx.xxx.xxx.XxxxAutoConfiguration
有多个时可以用逗号隔开:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.xxx.xxx.xxx.X01AutoConfiguration,/
com.xxx.xxx.xxx.X02AutoConfiguration,/
com.xxx.xxx.xxx.X03AutoConfiguration