@ConfigurationProperties注解与@EnableConfigurationProperties注解结合使用操作配置文件
在编写项目代码时,有些重要的信息将会放到配置文件中,以此达到更好的解耦效果,更好的模块整合。在 Spring Boot 项目中,为满足以上要求,我们将大量的参数配置在 application.properties 或 application.yml 文件中,通过 @ConfigurationProperties
注解,我们可以方便的获取这些参数值,把配置文件的信息读取并自动封装成实体类。再结合@EnableConfigurationProperties
注解使其注入spring容器中。
下面我们以一个具体的案例讲解两个注解的具体使用。
现在我们想要实现一个发送手机验证码的业务,我们可以利用阿里云或者腾讯云,如何就通过改写配置文件的信息,就能让程序自动地识别并使用相对应的平台呢?
首先我们先配置好application.yml文件:
sms:
# 短信类型,1:阿里,2:腾讯
type: 1
# 短信验证码有效时,单位为:秒
expire: 300
# 短信同一手机号最大发送条数
day_max: 10
# 阿里短信配置
ali:
regionId: ******
accessKeyId: ******
accessKeySecret: ******
signName: 案例演示
templateCode: ******
# 腾讯短信配置
tencent:
appId: ******
appKey: ******
templateId: ******
signName: 案例演示
这里我们在application.yml文件中配置了相关发送短信的配置。这里我们要达到根据type的不同取值而整个服务端采用相对应的短信发送平台。
现在编写SmsServiceProperties
类读取配置文件的相关信息
@Data
@ConfigurationProperties(prefix = "sms",ignoreInvalidFields = true) //从配置文件获取内容
public class SmsServiceProperties {
private int type = 1;
private long expire = 300L;
private long dayMax = 10L;
private final SmsServiceProperties.Ali ali = new SmsServiceProperties.Ali();
private final SmsServiceProperties.Tencent tencent = new SmsServiceProperties.Tencent();
public SmsServiceProperties() {
}
@Data
public static class Ali {
private String regionId = "cn-hangzhou";
private String accessKeyId;
private String accessKeySecret;
private String signName;
private String templateCode;
}
@Data
public static class Tencent {
private String appId;
private String appKey;
private String templateId;
private String signName;
}
}
这里我们就是使用了@ConfigurationProperties
注解用来映射配置文件的信息到实体类中。两个参数的作用:
prefix = "sms"
指定映射信息的前缀,和配置文件的前缀相同。然后程序就会在sms下去找信息名与实体类的属性名相匹配的,并进行赋值操作。ignoreInvalidFields=true
表示如果配置文件的信息名如果有和实体类的属性名对应不上的则直接忽略。
现在就是利用@EnableConfigurationProperties
注解使SmsServiceProperties生效并注入Springboot容器,编写配置类SmsAutoConfiguration:
@Configuration
//使SmsServiceProperties生效并注入Springboot容器,经常结合@ConfigurationProperties注解使用
@EnableConfigurationProperties({SmsServiceProperties.class})
public class SmsAutoConfiguration {
@Bean
@ConditionalOnMissingBean //保证只能注入一个SmsCodeService,不会重复注入,阿里和腾讯只会注入一个service就保证了和配置文件相配合
public SmsCodeService smsService(SmsServiceProperties properties) {
int type = properties.getType();
if (type == 1) {
return new AliSmsCodeService(properties);
}
return new TencentSmsCodeService(properties);
}
}
public class AliSmsCodeService implements SmsCodeService{}
public class TencentSmsCodeService implements SmsCodeService{}
这里的AliSmsCodeService与TencentSmsCodeService只需要实现一个共同的短信服务的相关接口SmsCodeService
,这样当系统调用SmsCodeService的发送短信验证码的方法时,spring就会去寻找实现了这个方法的具体实现类,而这个实现类就在SmsAutoConfiguration根据不同的type返回不同的实现类,以此达到解耦的效果。
这里还需要注意的是,虽然在代码中都体现了实现了SmsCodeService接口,但是记住一定不能在这两个类上面加@Service注解,否则这两个类都被注入到了spring容器中,系统就会不知道寻找哪个具体的实现类调用相关方法,你的type配置也就毫无意义。必须保证只会注入一个具体的实现类!