57. Spring 自定义properties升级篇

之前在两篇文章中都有简单介绍或者提到过 自定义属性的用法:

25.Spring Boot使用自定义的properties【从零开始学Spring Boot 

51.spring boot属性文件之多环境配置【从零开始学SpringBoot 

但是在实际开发过程中有更复杂的需求,我们在对properties进一步的升华。在本篇博客中您将会学到如下知识(这节中有对之前的知识的温故,对之前的升华):

(1) 在application.properties文件中添加自定义属性(单个属性使用);

(2) 在application.properties文件中添加自定义属性(多个属性使用);

(3) 配置数组注入;

(4) 松散的绑定;

(5) 参数的引用;

(6) 随机数;

(7) 使用自定义的配置文件company.properties怎么操作;

(8) 在方法上使用@Bean的时候如何进行注入;

(9) 自定义结构;

(10) 校验;

好了,本文大纲就这么多,那么我一起来看看每个知识点都应该怎么去操作吧。

(1) 在application.properties文件中添加自定义属性(单个属性使用);

       在这里我们新建一个maven java project进行测试,取名为:spring-boot-hello4。

对pom.xml基本的spring boot 配置,主要用到的一个核心依赖是:

<dependency>

                   <groupId>org.springframework.boot</groupId>

                   <artifactId>spring-boot-configuration-processor</artifactId>

                   <optional>true</optional>

</dependency>

官方中对于spring-boot-configuration-processor是这么说明的:

通过使用spring-boot-configuration-processorjar, 你可以从被@ConfigurationProperties注解的节点轻松的产生自己的配置元数据文件。该jar包含一个在你的项目编译时会被调用的Java注解处理器。想要使用该处理器,你只需简单添加spring-boot-configuration-processor依赖。

好了,官方已经说得很清楚了,这个依赖主要可以在代码中轻松的使用@ConfigurationProperties注解注入属性文件配置的属性值。

单属性注入的比较简单,只需要在application.properties加入配置,如下:

#key = value的形式;

filePathLocation = d:/data/files

那么在对应需要使用的类中使用如下代码进行引入:

@Value("${filePathLocation}")

privateString filePathLocation;

这里使用@Value注解就可以为我们的变量filePathLocation设置上我们在application.properties文件中设置的key值了。

在实际开发中可能我们期望的是,如果没有设置key的话,设置一个默认值,使用如下代码即可实现(以上@Value的使用方式如果在没有设置key的话是会抛出异常的):

@Value("${filePathLocation1:d:/data/myfiles}")

privateString filePathLocation1;

这里的filePathLocation1我们并没有在application.properties文件中进行指定,但是查看打印信息是可以看到我们设置的默认值的,所以设置默认值的方式就是:

@Value(“${key:defaultVlaue}”)的形式进行设置。

(2) 在application.properties文件中添加自定义属性(多个属性使用);

       多属性的设置也可以属性单属性的注入方式,但是这种方式不好,那么怎么比较优雅的注入多个属性值进行使用了。假设我们在application.properties定义了如下的属性:

#公司简称;

com.kfit.company.name=知远信科

#公司位置;

com.kfit.company.location=北京海淀区

#公司联系方式;

com.kfit.company.mobile= 110****1195

#公司员工人数;

com.kfit.company.employCount= 100

接下来我们定义一个ComapnyProperties类进行设置这些参数。

package com.kfit.properties;

 

importorg.springframework.boot.context.properties.ConfigurationProperties;

importorg.springframework.stereotype.Component;

 

//prefix设置key的前缀;

@ConfigurationProperties(prefix ="com.kfit.company")

@Component

publicclass CompanyProperties {

      

       private Stringname;

       private Stringlocation;

       private Stringmobile;

       privateintemployCount;

       public StringgetName() {

              returnname;

       }

       publicvoid setName(Stringname) {

              this.name =name;

       }

       public StringgetLocation() {

              returnlocation;

       }

       publicvoidsetLocation(Stringlocation) {

              this.location =location;

       }

       public StringgetMobile() {

              returnmobile;

       }

       publicvoidsetMobile(Stringmobile) {

              this.mobile =mobile;

       }

       publicintgetEmployCount() {

              returnemployCount;

       }

       publicvoid setEmployCount(intemployCount) {

              this.employCount =employCount;

       }

       @Override

       public StringtoString() {

              return"CompanyProperties[name=" +name + ", location=" +location + ", mobile=" +mobile + ",employCount="

                            +employCount +"]";

       }

}

那么之后我们就可以使用如下代码注入到要使用的这些属性的类进行使用了:

@Autowired

privateCompanyProperties companyProperties;

这里需要注意下:

第一:我们使用了@ConfigurationProperties(prefix= "com.kfit.company")快速注入我们的属性,这里prefix是key的公共部分。

第二:这里我们使用@Component注解为spring 管理的类,那么在别的类才可以进行注入使用。

第三:在之前的文章中我们并没有使用@Component进行注册为spring 容器中,而是使用了@EnableConfigurationProperties({WiselySettings.class})  这样的方式进行注入的。这两种方式都可以。

(3) 配置数组注入;

我们在application.properties定义数组:

# 员工列表

com.kfit.company.employs[0]=张三

com.kfit.company.employs[1]=李四

com.kfit.company.employs[2]=王五

类似这样的定义那么在对应的CompanyProperties文件中怎么接收呢?很简单,定义List<String>接收就可以了,代码如下:

privateList<String> employs = new ArrayList<String>();

这里的属性名称employs需要和application.properties文件的key是对应的。

这样employs注入了配置中的数据,打印为如下:

[张三, 李四, 王五]

(4) 松散的绑定;

Spring Boot使用宽松的规则用于绑定属性到@ConfigurationProperties beans,所以Environment属性名和bean属性名不需要精确匹配。常见的示例中有虚线分隔的(比如,context-path绑定到contextPath),环境属性大写转为小写字母(比如:PORT绑定port)。

示例:

在application.properties文件中的配置:

com.kfit.company.firstName = lin

com.kfit.company.logo-path = d:/data/files/logo.png

com.kfit.company.COMPANY_FULLNAME =北京知远科技公司

对应的CompanyProperties类中的对应定义:

  //对应:com.kfit.company.firstName =lin

       private StringfirstName;

      

       //对应:com.kfit.company.logo-path= d:/data/files/logo.png

       private StringlogoPath;

      

       //对应:com.kfit.company.COMPANY_FULLNAME=北京知远科技公司

       private StringcompanyFullname;

      

       privateList<String>employs =new ArrayList<String>();

看到这里,你是否终于知道为什么context-path,spring.jpa.show-sql

其实是被解释为contextPath和showSql了,不然要是指定定义一个show-sql变量是无法编译通过的,oh,原来是这么回事呢,这真是太神奇了,就是因为编程无奇不有,所以才有那么多人爱编程。

(5) 参数的引用;

各个参数之间也可以直接引用来使用,就像下面的设置:

com.kfit.blog.desc=${com.kfit.blog.name}正在写《${com.kfit.blog.title}

这个就很好理解了,使用${key}的方式进行引用。

(6) 随机数;

在一些情况下,有些参数我们需要希望它不是一个固定的值,比如密钥、服务端口等。Spring Boot的属性配置文件中可以通过${random.xxx}来产生int值、long值或者string字符串,来支持属性的随机值。

随机字符串

com.kfit.blog.value=${random.value} 

随机int

com.kfit.blog.number=${random.int} 

随机long

com.kfit.blog.bignumber=${random.long} 

# 10以内的随机数

com.kfit.blog.test1=${random.int(10)} 

# 10-20的随机数

com.kfit.blog.test2=${random.int[10,20]} 

好了,这些在之前的文章都有介绍过了,就不多说了。

(7) 使用自定义的配置文件company.properties怎么操作;

如果我们自己定义一个company.properties文件,

#key = value的形式;

filePathLocation = d:/data/files

 

#公司简称;

com.kfit.company.name =知远信科-custom

#公司位置;

com.kfit.company.location =北京海淀区-custom

#公司联系方式;

com.kfit.company.mobile =110****1195-custom

#公司员工人数;

com.kfit.company.employCount = 100

# 员工列表

com.kfit.company.employs[0]=张三-custom

com.kfit.company.employs[1]=李四-custom

com.kfit.company.employs[2]=王五-custom

 

com.kfit.company.firstName = lin-custom

com.kfit.company.logo-path =d:/data/files/logo.png-custom

com.kfit.company.COMPANY_FULLNAME =北京知远科技公司-custom

这个定义就是我们刚刚提到的一些配置,那么怎么引入了,如果使用上面的CompanyProperties的方式肯定是不行了,那么怎么呢?其实很简单,只需要在CompanyProperties稍微修改下即可,修改的地方如下:

@ConfigurationProperties(

                  prefix= "com.kfit.company",

            locations="classpath:company.properties")

大家注意,这里唯一不一样的地方是加入了一个属性locations指定了我们要使用的配置文件路径和名称,如果我们的配置文件不在application.properties下,可以这么定义:

classpath:config/company.properties

好了这一个知识点就这么简单,只要掌握要点,一句代码就可以搞定。

(8) 在方法上使用@Bean的时候如何进行注入;

       这个需求点是怎么产生的呢?我们经常会配置多个数据源,那么我们有些配置还是希望从application.properties文件中进行读取,那么自然而然的在我们定义的@bean中就需要能够读取配置文件的属性。这里我们简单做个试验,我们定义CompanyProperties3,具体代码如下:






package com.kfit.properties;

 

import java.util.ArrayList;

import java.util.List;

 

public class CompanyProperties3 {

      

       private Stringname;

       private Stringlocation;

       private Stringmobile;

       private int employCount;

      

       //对应:com.kfit.company.firstName=lin

       private StringfirstName;

      

       //对应:com.kfit.company.logo-path= d:/data/files/logo.png

       private StringlogoPath;

      

       //对应:com.kfit.company.COMPANY_FULLNAME=北京知远科技公司

       private StringcompanyFullname;

      

       privateList<String>employs =new ArrayList<String>();

      

      

       public StringgetFirstName() {

              returnfirstName;

       }

       public voidsetFirstName(String firstName) {

              this.firstName =firstName;

       }

       public StringgetLogoPath() {

              returnlogoPath;

       }

       public voidsetLogoPath(String logoPath) {

              this.logoPath =logoPath;

       }

       public StringgetCompanyFullname() {

              returncompanyFullname;

       }

       public voidsetCompanyFullname(String companyFullname) {

              this.companyFullname =companyFullname;

       }

       publicList<String> getEmploys() {

              returnemploys;

       }

       public voidsetEmploys(List<String> employs) {

              this.employs =employs;

       }

       public StringgetName() {

              returnname;

       }

       public void setName(String name) {

              this.name =name;

       }

       public StringgetLocation() {

              returnlocation;

       }

       public voidsetLocation(String location) {

              this.location =location;

       }

       public StringgetMobile() {

              returnmobile;

       }

       public voidsetMobile(String mobile) {

              this.mobile =mobile;

       }

       public intgetEmployCount() {

              returnemployCount;

       }

       public void setEmployCount(intemployCount) {

              this.employCount =employCount;

       }

       @Override

       public StringtoString() {

              return"CompanyProperties[name=" +name + ", location=" +location + ", mobile=" +mobile + ",employCount="

                            +employCount +",firstName=" +firstName +", logoPath=" +logoPath +", companyFullname="

                            +companyFullname +",employs=" +employs +"]";

       }

}

注意这里的代码和以上不一样的是类上的注解全没有了,之后我们在App.java启动类中或者其它的类也是可以的,使用@Bean的方式进行注入。

   @Bean

       @ConfigurationProperties(prefix ="com.kfit.company")

       publicCompanyProperties3companyProperties3(){

              returnnew CompanyProperties3();

       }

那么在其它的类中我们就使用@Autowired进行注入使用了,如下:

@Autowired

privateCompanyProperties3 companyProperties3;

是不是很好玩呢。

(9) 自定义结构;

       对于复杂的配置或嵌套的kv,我们可以编写自定义结构属性以更好的方式进行管理。

比如我们在application.properties文件中有如下信息:

com.kfit.employForzs.name =张三

com.kfit.employForzs.age = 20

com.kfit.employForzs.gender =

 

com.kfit.employForls.name =李四

com.kfit.employForls.age = 25

com.kfit.employForzs.gender =

com.kfit.properties.CompanyEmployee的代码如下:

package com.kfit.properties;

 

importorg.springframework.boot.context.properties.ConfigurationProperties;

importorg.springframework.stereotype.Component;

 

//prefix设置key的前缀;

@ConfigurationProperties(prefix ="com.kfit")

@Component

public class CompanyEmployee {

      

       privateCompanyEmployeeInfoemployForzs;

      

       privateCompanyEmployeeInfoemployForls;

      

       publicCompanyEmployeeInfo getEmployForzs() {

              returnemployForzs;

       }

 

       public voidsetEmployForzs(CompanyEmployeeInfo employForzs) {

              this.employForzs =employForzs;

       }

 

       publicCompanyEmployeeInfo getEmployForls() {

              returnemployForls;

       }

 

       public voidsetEmployForls(CompanyEmployeeInfo employForls) {

              this.employForls =employForls;

       }

 

       public static class CompanyEmployeeInfo{

              private Stringname;

              private int age;

              private Stringgender;

              public StringgetName() {

                     returnname;

              }

              public void setName(String name) {

                     this.name =name;

              }

              public int getAge() {

                     returnage;

              }

              public void setAge(intage) {

                     this.age =age;

              }

              public StringgetGender() {

                     returngender;

              }

              public voidsetGender(String gender) {

                     this.gender =gender;

              }

              @Override

              public StringtoString() {

                     return"EmployForzs[name=" +name + ", age=" +age + ", gender=" +gender + "]";

              }

       }

 

       @Override

       public StringtoString() {

              return"CompanyEmployee[employForzs=" +employForzs + ", employForls=" +employForls + "]";

       }

}

观察以上的代码我们定义了一个内部静态类进行处理相同的属性,那么在外部类中定义两个变量进行接收application.properties文件中的配置信息。

之后在其它类就可以使用@Autowired进行注入使用了。

 

(10) 校验;

       当我们使用@ConfigurationProperties的时候,我们希望对一些参数进行校验,比如有些参数为空或者数字超出的限制就抛出异常信息,那么这个怎么操作呢?

在application.properties文件中加入:

com.kfit.company.url= http://www.kfit.com

在CompanyProperties类中加入:

@URL

privateString url;

这里使用了@URL对url进行校验,如果是非法的url在启动的时候是会抛出异常信息的。

其中@URL对应的包路径为:org.hibernate.validator.constraints.URL

那么还有其它的什么校验器呢?看下文:

@Max(value = 99)

privateintemployCount;

定义最大值只能是99,那么如果运行的话,显然就会报错了,因为之前我们配置的值是100,那么就会看到控制台抛出异常信息:

defaultmessage [最大不能超过99]

这里只是截取了一小部分异常信息,具体的异常信息是可以参数那个参数的设置有问题的。

既然有最大值就有最小值的配置:

@Max(value = 1000)

@Min(value = 1)

privateintemployCount;

接着往下看:

@NotNull

privateString name;

@NotNull说明name不能为null,如果为null就抛出异常。

接着往下看:

@NotEmpty

privateString location;

@NotEmpty不能为空,当没有定义key和key的值为空字符的时候都会抛出异常信息。

在validation-api下包javax.validation.constraints下还有其它的校验器,大家可以根据需要自行学习。当然校验器是可以自定定义的,大家可以自己在扩展下,好了这个章节就介绍到这里了。



购买完整视频,请前往:http://www.mark-to-win.com/TeacherV2.html?id=287