57. Spring 自定义properties升级篇【从零开始学Spring Boot】

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 注解ConfigurationProperties和EnableAutoConfiguration的区别: @EnableConfigurationProperties tells Spring to treat this class as a consumer of application.

 注解ConfigurationProperties和EnableAutoConfiguration的区别:

@EnableConfigurationProperties tells Spring to treat this class as a consumer of application.yml/properties values(

{@link ConfigurationProperties} beans can be registered in the standard way (for  example using {@link Bean @Bean} methods)
or, for convenience, can be specified   directly on this annotation.


@ConfigurationProperties tells Spring what section this class represents.

Annotation for externalized configuration(外面化配置). Add this to a class definition or a{@code @Bean} method in a {@code @Configuration} class 
if you want to bind and validate  some external Properties (e.g. from a .properties file).

 




 

 

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

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

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

但是在实际开发过程中有更复杂的需求,我们在对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-processor jar, 你可以从被@ConfigurationProperties注解的节点轻松的产生自己的配置元数据文件。该jar包含一个在你的项目编译时会被调用的Java注解处理器。想要使用该处理器,你只需简单添加spring-boot-configuration-processor依赖。

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

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

#key = value的形式;  
filePathLocation = d:/data/files  

 

那么在对应需要使用的类中使用如下代码进行引入:
@Value("${filePathLocation}")  
private String filePathLocation;  

 

 

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

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

@Value("${filePathLocation1:d:/data/myfiles}")  
private String 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类进行设置这些参数。

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.stereotype.Component;

//prefix设置key的前缀;
@ConfigurationProperties(prefix = "com.kfit.company")
@Component
public class CompanyProperties {
    private String name;
    private String location;
    private String mobile;
    private int employCount;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public int getEmployCount() {
        return employCount;
    }

    public void setEmployCount(int employCount) {
        this.employCount = employCount;
    }

    @Override
    public String toString() {
        return "CompanyProperties{" +
                "name='" + name + '\'' +
                ", location='" + location + '\'' +
                ", mobile='" + mobile + '\'' +
                ", employCount=" + employCount +
                '}';
    }
}

 

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

@Autowired  
private CompanyProperties 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>接收就可以了,代码如下:

private List<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 String firstName;  
   
  //对应:com.kfit.company.logo-path = d:/data/files/logo.png  
  private String logoPath;  
   
  //对应:com.kfit.company.COMPANY_FULLNAME = 北京知远科技公司  
  private String companyFullname;  
   
  private List<String> employs = new ArrayList<String>();  

 

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

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

(5) 参数的引用;

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

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

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

 

(6) 随机数;

在一些情况下,有些参数我们需要希望它不是一个固定的值,比如密钥、服务端口等。Spring Boot的属性配置文件中可以通过${random}来产生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,具体代码如下:

Java代码  
  1. package com.kfit.properties;  
  2.    
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.    
  6. public class CompanyProperties3 {  
  7.      
  8.     private String name;  
  9.     private String location;  
  10.     private String mobile;  
  11.     private int employCount;  
  12.      
  13.     //对应:com.kfit.company.firstName = lin  
  14.     private String firstName;  
  15.      
  16.     //对应:com.kfit.company.logo-path = d:/data/files/logo.png  
  17.     private String logoPath;  
  18.      
  19.     //对应:com.kfit.company.COMPANY_FULLNAME = 北京知远科技公司  
  20.     private String companyFullname;  
  21.      
  22.     private List<String> employs = new ArrayList<String>();  
  23.      
  24.      
  25.     public String getFirstName() {  
  26.        return firstName;  
  27.     }  
  28.     public void setFirstName(String firstName) {  
  29.        this.firstName = firstName;  
  30.     }  
  31.     public String getLogoPath() {  
  32.        return logoPath;  
  33.     }  
  34.     public void setLogoPath(String logoPath) {  
  35.        this.logoPath = logoPath;  
  36.     }  
  37.     public String getCompanyFullname() {  
  38.        return companyFullname;  
  39.     }  
  40.     public void setCompanyFullname(String companyFullname) {  
  41.        this.companyFullname = companyFullname;  
  42.     }  
  43.     public List<String> getEmploys() {  
  44.        return employs;  
  45.     }  
  46.     public void setEmploys(List<String> employs) {  
  47.        this.employs = employs;  
  48.     }  
  49.     public String getName() {  
  50.        return name;  
  51.     }  
  52.     public void setName(String name) {  
  53.        this.name = name;  
  54.     }  
  55.     public String getLocation() {  
  56.        return location;  
  57.     }  
  58.     public void setLocation(String location) {  
  59.        this.location = location;  
  60.     }  
  61.     public String getMobile() {  
  62.        return mobile;  
  63.     }  
  64.     public void setMobile(String mobile) {  
  65.        this.mobile = mobile;  
  66.     }  
  67.     public int getEmployCount() {  
  68.        return employCount;  
  69.     }  
  70.     public void setEmployCount(intemployCount) {  
  71.        this.employCount = employCount;  
  72.     }  
  73.     @Override  
  74.     public String toString() {  
  75.        return "CompanyProperties [name=" + name + ", location=" + location + ", mobile=" + mobile + ", employCount="  
  76.               + employCount + ", firstName=" + firstName + ", logoPath=" + logoPath + ", companyFullname="  
  77.               + companyFullname + ", employs=" + employs + "]";  
  78.     }  
  79. }  

 

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

    @Bean

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

    public CompanyProperties3 companyProperties3(){

       returnnew CompanyProperties3();

    }

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

Java代码  
  1. @Autowired  
  2. private CompanyProperties3 companyProperties3;  

 

是不是很好玩呢。

 

(9) 自定义结构;

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

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

Java代码  
  1. com.kfit.employForzs.name =张三  
  2. com.kfit.employForzs.age = 20  
  3. com.kfit.employForzs.gender =男  
  4.    
  5. com.kfit.employForls.name =李四  
  6. com.kfit.employForls.age = 25  
  7. com.kfit.employForzs.gender =女  

 

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

Java代码  
  1. package com.kfit.properties;  
  2.    
  3. import org.springframework.boot.context.properties.ConfigurationProperties;  
  4. import org.springframework.stereotype.Component;  
  5.    
  6. //prefix设置key的前缀;  
  7. @ConfigurationProperties(prefix = "com.kfit")  
  8. @Component  
  9. public class CompanyEmployee {  
  10.      
  11.     private CompanyEmployeeInfo employForzs;  
  12.      
  13.     private CompanyEmployeeInfo employForls;  
  14.      
  15.     public CompanyEmployeeInfo getEmployForzs() {  
  16.        return employForzs;  
  17.     }  
  18.    
  19.     publicvoid setEmployForzs(CompanyEmployeeInfo employForzs) {  
  20.        this.employForzs = employForzs;  
  21.     }  
  22.    
  23.     public CompanyEmployeeInfo getEmployForls() {  
  24.        return employForls;  
  25.     }  
  26.    
  27.     publicvoid setEmployForls(CompanyEmployeeInfo employForls) {  
  28.        this.employForls = employForls;  
  29.     }  
  30.    
  31.     public static class CompanyEmployeeInfo {  
  32.        private String name;  
  33.        private int age;  
  34.        private String gender;  
  35.        public String getName() {  
  36.            return name;  
  37.        }  
  38.        publicvoid setName(String name) {  
  39.            this.name = name;  
  40.        }  
  41.        public int getAge() {  
  42.            return age;  
  43.        }  
  44.        public void setAge(intage) {  
  45.            this.age = age;  
  46.        }  
  47.        public String getGender() {  
  48.            returngender;  
  49.        }  
  50.        public void setGender(String gender) {  
  51.            this.gender = gender;  
  52.        }  
  53.        @Override  
  54.        public String toString() {  
  55.            return "EmployForzs [name=" + name + ", age=" + age + ", gender=" + gender + "]";  
  56.        }  
  57.     }  
  58.    
  59.     @Override  
  60.     public String toString() {  
  61.        return "CompanyEmployee [employForzs=" + employForzs + ", employForls=" + employForls + "]";  
  62.     }  
  63. }  

 

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

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

 

(10) 校验;

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

在application.properties文件中加入:

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

在CompanyProperties类中加入:

@URL

private String url;

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

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

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

@Max(value = 99)

private int employCount;

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

default message [最大不能超过99]

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

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

@Max(value = 1000)

@Min(value = 1)

private int employCount;

接着往下看:

@NotNull

private String name;

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

接着往下看:

@NotEmpty

private String location;

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

 

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

 

 Spring Boot 系列博客】

54. spring boot日志升级篇—logback【从零开始学Spring Boot】

52. spring boot日志升级篇—log4j多环境不同日志级别的控制【从零开始学Spring Boot】 

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

50. Spring Boot日志升级篇—log4j【从零开始学Spring Boot】

49. spring boot日志升级篇—理论【从零开始学Spring Boot】

48. spring boot单元测试restfull API【从零开始学Spring Boot】

47. Spring Boot发送邮件【从零开始学Spring Boot】

46. Spring Boot中使用AOP统一处理Web请求日志

45. Spring Boot MyBatis连接Mysql数据库【从零开始学Spring Boot】

44. Spring Boot日志记录SLF4J【从零开始学Spring Boot】

43. Spring Boot动态数据源(多数据源自动切换)【从零开始学Spring Boot】

42. Spring Boot多数据源【从零开始学Spring Boot】

41. Spring Boot 使用Java代码创建Bean并注册到Spring中【从零开始学Spring Boot】

40. springboot + devtools(热部署)【从零开始学Spring Boot】 

39.4 Spring Boot Shiro权限管理【从零开始学Spring Boot】

39.3 Spring Boot Shiro权限管理【从零开始学Spring Boot】

39.2. Spring Boot Shiro权限管理【从零开始学Spring Boot】

39.1 Spring Boot Shiro权限管理【从零开始学Spring Boot】

38 Spring Boot分布式Session状态保存Redis【从零开始学Spring Boot】 

37 Spring Boot集成EHCache实现缓存机制【从零开始学Spring Boot】 

36 Spring Boot Cache理论篇【从零开始学Spring Boot】

35 Spring Boot集成Redis实现缓存机制【从零开始学Spring Boot】 

34Spring Boot的启动器Starter详解【从零开始学Spring Boot】

33 Spring Boot 监控和管理生产环境【从零开始学Spring Boot】

32 Spring Boot使用@SpringBootApplication注解【从零开始学Spring Boot】 

31 Spring Boot导入XML配置【从零开始学Spring Boot】

更多查看博客: http://412887952-qq-com.iteye.com/

http://412887952-qq-com.iteye.com/blog/2311017

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
1天前
|
XML Java 应用服务中间件
Spring Boot 两种部署到服务器的方式
本文介绍了Spring Boot项目的两种部署方式:jar包和war包。Jar包方式使用内置Tomcat,只需配置JDK 1.8及以上环境,通过`nohup java -jar`命令后台运行,并开放服务器端口即可访问。War包则需将项目打包后放入外部Tomcat的webapps目录,修改启动类继承`SpringBootServletInitializer`并调整pom.xml中的打包类型为war,最后启动Tomcat访问应用。两者各有优劣,jar包更简单便捷,而war包适合传统部署场景。需要注意的是,war包部署时,内置Tomcat的端口配置不会生效。
50 17
Spring Boot 两种部署到服务器的方式
|
8天前
|
缓存 安全 Java
Spring Boot 3 集成 Spring Security + JWT
本文详细介绍了如何使用Spring Boot 3和Spring Security集成JWT,实现前后端分离的安全认证概述了从入门到引入数据库,再到使用JWT的完整流程。列举了项目中用到的关键依赖,如MyBatis-Plus、Hutool等。简要提及了系统配置表、部门表、字典表等表结构。使用Hutool-jwt工具类进行JWT校验。配置忽略路径、禁用CSRF、添加JWT校验过滤器等。实现登录接口,返回token等信息。
154 12
|
14天前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
59 8
|
26天前
|
Java Spring
【Spring配置】创建yml文件和properties或yml文件没有绿叶
本文主要针对,一个项目中怎么创建yml和properties两种不同文件,进行配置,和启动类没有绿叶标识进行解决。
|
1月前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
107 14
|
26天前
|
缓存 前端开发 Java
【Spring】——SpringBoot项目创建
SpringBoot项目创建,SpringBootApplication启动类,target文件,web服务器,tomcat,访问服务器
|
2月前
|
监控 Java 数据库连接
详解Spring Batch:在Spring Boot中实现高效批处理
详解Spring Batch:在Spring Boot中实现高效批处理
353 12
|
1月前
|
负载均衡 Java 开发者
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
172 5
|
8月前
|
XML 安全 Java
深入实践springboot实战 蓄势待发 我不是雷锋 我是知识搬运工
springboot,说白了就是一个集合了功能的大类库,包括springMVC,spring,spring data,spring security等等,并且提供了很多和可以和其他常用框架,插件完美整合的接口(只能说是一些常用框架,基本在github上能排上名次的都有完美整合,但如果是自己写的一个框架就无法实现快速整合)。
|
5月前
|
缓存 Java Maven
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
160 1