avatar

SpringBoot配置

配置文件

Springboot使用一个全局的配置文件,配置文件名是固定的,可以在运行jar包时使用--spring.config.name属性去指定名称,--spring.config.location属性用于指定特定的配置文件路径

  • applocation.properties
  • application.yml

配置文件的作用:修改SpringBoot自动配置的默认值。

配置文件优先级

  • 根目录下的/config目录下的配置文件
  • 根目录下的配置文件
  • 类路径下的/config目录下的配置文件
  • 类路径下的配置文件
  • 当yaml与properties同时存在时,properties文件优先级最高(springboot 2.4之前);yaml>properties 是在springBoot 2.4之后

    YAML

    .yml是YAML(YAML Ain’t Markup Language)语言的文件,以数据为中心,比json、xml等更适合做配置文件

    YAML语法

    YAML基本语法

    • K:(空格)V:表示一对键值对(空格必须有);
    • 以空格的缩进来控制层级关系;只要左对齐的一列数据都是同一个层级的
    server:
    port: 8080
    path: /hello
    • 属性和值也是大小写敏感的。

    值的写法

    YAML 支持的数据结构有三种
    对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
    数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
    纯量(scalars):单个的、不可再分的值
    YAML 语言教程
    对象

    对象的一组键值对,使用冒号结构表示。

    animal: pets
    hash: { name: Steve, foo: bar } #行内写法
    friend :
    fname : haha
    age : 20
    数组

    一组连词线开头的行,构成一个数组。

    - Cat
    - Dog
    - Goldfish
    animal: [Cat, Dog] #行内写法
    复合结构

    对象和数组可以结合使用,形成复合结构。

    languages:
    - Ruby
    - Perl
    - Python
    websites:
    YAML: yaml.org
    Ruby: ruby-lang.org
    Python: python.org
    Perl: use.perl.org
    纯量

    纯量是最基本的、不可再分的值。以下数据类型都属于 JavaScript 的纯量。

    • 数值直接以字面量的形式表示。
    • 布尔值用true和false表示。
    • null用~表示。
    • 时间采用 ISO8601 格式
    iso8601: 2001-12-14t21:59:43.10-05:00
    • 日期采用复合 iso8601 格式的年、月、日表示。
    date: 1976-07-31
    • YAML 允许使用两个感叹号,强制转换数据类型。
    字符串

    字符串默认不使用引号表示。

    • 如果字符串之中包含空格或特殊字符,需要放在引号之中。
    • 单引号和双引号都可以使用,双引号不会对特殊字符转义。
    name : "zhangsan \n lisi"  -> 输出  zhangsan 换行 lisi
    name : 'zhangsan \n lisi' -> 输出 zhangsan \n lisi
    • 字符串可以写成多行,从第二行开始,必须有一个单空格缩进。换行符会被转为空格。
    • 多行字符串可以使用|保留换行符,也可以使用>折叠换行。
    this: |
    Foo
    Bar
    that: >
    Foo
    Bar
    • +表示保留文字块末尾的换行,-表示删除字符串末尾的换行。

    配置文件值注入

    1、我们编写实体类,bean类
    2、在yml文件中编写对应的配置信息
    3、在要注入的类中加入以下注解

    • @Component:将类加载到SpringBoot容器中
    • @ConfigurationProperties(prefix = “”) :将类与配置文件信息一一映射,prefix是对应的映射父对象,默认从全局配置文件中获取值

然后以注入的形式加载到我们使用的类中的时候就会带着配置文件的信息了。

yml文件

person :
lastname : zhangsan
age: 18
boss : true
birth : 2017/12/12
maps : {k1: v1,k2: v2}
list :
- lisi
- zhaoliu
dog :
name : 小狗
age : 2

对应的javabean

/**
* 将配置文件中的每一个属性的值映射到这个组件中
* @ConfigurationProperties 告诉SpringBoot将奔雷中的所有属性和配置文件中相关的配置进行绑定
* perfix = “person”: 配置文件中哪个下面的所有属性进行一一映射
ConfigurationProperties 既可以标注在类上,同样也可以标注在方法上。
* 只有这个组件是容器中的组件,才能使用容器提供的功能
*/
@Component
@ConfigurationProperties(prefix = "person")
public class person {
private String lastname;
private Integer age;
private Boolean boss;
private Date birth;

public void setLastname(String lastername) {
this.lastname = lastername;
}

public void setAge(Integer age) {
this.age = age;
}

public void setBoss(Boolean boss) {
this.boss = boss;
}

public void setBirth(Date birth) {
this.birth = birth;
}

public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}

public void setList(List<Object> list) {
this.list = list;
}

public void setDog(Dog dog) {
this.dog = dog;
}

private Map<String,Object> maps;
private List<Object> list;
private Dog dog;

@Override
public String toString() {
return "person{" +
"lastname='" + lastname + '\'' +
", age=" + age +
", boss=" + boss +
", birth=" + birth +
", maps=" + maps +
", list=" + list +
", dog=" + dog +
'}';
}

public String getLastname() {
return lastname;
}

public Integer getAge() {
return age;
}

public Boolean getBoss() {
return boss;
}

public Date getBirth() {
return birth;
}

public Map<String, Object> getMaps() {
return maps;
}

public List<Object> getList() {
return list;
}

public Dog getDog() {
return dog;
}
}
public class Dog {
private String name;
private Integer age;

@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}

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

public void setAge(Integer age) {
this.age = age;
}

public String getName() {
return name;
}

public Integer getAge() {
return age;
}
}

导入配置文件处理器

导入配置文件处理器以后,我们再进行编写配置的时候就有提示了

<!--导入配置文件处理器,配置文件进行绑定就会有提示-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

单元测试

单元测试必须都是pulic的方法,不然没有办法执行
要注入的javabean类必须自动注入的方式,new是不会去读配置文件的。
代码演示

/**
* 可以很方便的在测试期间进行自动注入
*/
//用Spring的驱动器来跑
@RunWith(SpringRunner.class)
@SpringBootTest//说明是Spring的单元测试
public class SpringbootquickApplicationTests {
@Autowired
person p;
@Test
public void contextLoads() {
System.out.print(p);
}
}

== 要注意的一点就是:javabean必须有get,set方法才可以。==

使用properties文件进行配置

#idea properties文件配置成utf-8编码
person.age = 18
person.birth= 2017/12/12
person.boss=false
person.lastname=张三
person.maps.k1 = v1
person.maps.k2 = 12
person.list=a,b,c
person.dog.name = dag
person.dog.age = 12

这里需要注意的是,在proterties文件中我们使用中文的时候可能会出现乱码现象,记得把idea的配置文件编码格式设置为utf-8允许转换成ASCII码
其他不用变,properties文件的优先级比yml高,他俩获取的方式都是一样的无需改动

其他获取方式

@Value

spring中对于加载bean的时候会用到用value的方式进行读取,那么SpringBoot就是使用了这个方式

/**
* Spring中bean的加载方式
* <bean class="person">
* <property name="lastername" value="字面量/${key}从环境变量、配置文件中取值/#{SpEl}"></>
* <bean/>
*/
@Value("${person.lastname}")
private String lastname;

注解的区别

@ConfigurationProperties @Value
功能 批量注入配置文件中的属性 一个一个指定
松散绑定(松散语法) 支持 不支持
支持SpEL 不支持 支持
JSR303数据校验 支持 不支持
复杂类型封装 支持 不支持
#### JSR303数据校验使用方法

1、在bean类的加上注解@Validated
2、在要进行数据校验的地方加入相应的注解即可

@Validated
public class person {
@Email
private String Email;

松散绑定

  • person.firstName:使用标准写法
  • person.first-name:大写用-
  • person.first_name:大写用_
  • PERSON_FIRST_NAME: 系统推荐这种写法

@PropertySource&@ImportResource

@PropertySource

用于加载指定的配置文件

  • 使用PropertySource时必须有ConfigurationProperties注解,不然取不到值
  • PropertySource后面获取配置文件的时候必须将文件名和后缀名都写上,不然报错
@ConfigurationProperties(prefix = "person")
@PropertySource(value = {"classpath:person.properties"})

@ImportResource

导入Spring的配置文件,让配置文件内容生效
SpringBoot中没有Spring的配置文件,我们自己编写的配置文件不能自动识别
想让Spring配置文件生效,就需要使用这个注解
在主配置类加上注解

@ImportResource(locations = {"classpath:beans.xml"})//配置文件是自己定义的
@SpringBootApplication
public class SpringbootquickApplication {

public static void main(String[] args) {
SpringApplication.run(SpringbootquickApplication.class, args);
}

}

SpringBoot推荐给容器中添加组件的方式,推荐使用全注解的方式

  • 配置类=======Spring配置文件
  • 使用@Bean给容器中添加组件
/**
* @Configuration 指明当前类是一个配置类,来替代之前spring的配置文件
*
* 在配置文件中使用<bean><bean/>标签来添加组件
*/
@Configuration
public class MyAppConfig {

//将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名
@Bean
public HelloService helloServcice()
{
System.out.println("配置类@Beang给容器添加组件");
return new HelloService();
}
}

配置文件占位符

RandomValuePropertySource:

配置文件中可以使用随机数

  • ${random.int}
  • ${random.value}
  • ${random.long}
  • ${random.int(10)}
  • ${random.int[1024,65536]}

属性配置占位符

可以在配置文件中引用前面配置过的属性(优先级前面配置过的这里都能用)
${app.name:默认值}来指定找不到属性时的默认值

app.name = zhangsan
app.address = ${app.name:null} + beijing

Profile

Profile是Spring对不同环境提供不同配置功能的支持,可以通过激活、指定参数等方式快速切换环境

多Profile文件

我们在主配置文件编写的时候,文件名可以是application-{profile}-properties/yml
默认使用application。properties作为配置文件

yml多文档块

server:
port: 8081
spring:
profiles:
active: dev #激活哪个环境来实现
--- #这个作用是分文档块
server:
port: 8082
spring:
profiles: dev
---
server:
port: 8083
spring:
profiles: pro #配置环境

激活支持Profile

  • 在配置文件中指定spring.profiles.active= dev 来激活
  • 命令行来激活 –spring.profiles.active = dev
    • 在IDEA中进行编写
    • 打包称为jar包运行的时候编写
  • 利用jvm参数 -Dspring.profilers.active=dev

配置文件加载位置

SpringBoot启动扫描以下位置的application.properties或者时application.yml文件作为SpringBooy的默认配置文件

  • file:./config/
  • file:./
  • classpath:/config/
  • classpath:/
    以上是按照优先级从高到低地顺序,所有位置地文件都会被加载,高优先级配置内容会覆盖低优先级配置地内容
    我们也可以通过配置spring.config.location来改变默认配置
  • 项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候指定配置文件的新位置
  • 指定配置文件和默认加载的配置文件一起被启动,形成互补配置。
    高低优先级会形成互补配置,也就是说高优先级没有地配置在低优先级存在不会被覆盖。

SpringBoot支持多种外部配置方式

springBoot可以从以下位置读,下面是顺序是优先级

  • 命令行参数(多个配置按照空格分开)
  • 来自java:comp/env的JNDI属性
  • java系统属性(System.getProperties)
  • 操作系统环境变量
  • RandomValuePropertySource配置的random.*属性
  • jar包外部的application-{profile}.properties或者application.yml(带spring.profile配置文件)
  • jar内部的application-{profile}.properties或者application.yml(带spring.profile配置文件)
  • jar外部的application-{profile}.properties或者application.yml(不带spring.profile配置文件)
  • jar内部的application-{profile}.properties或者application.yml(不带spring.profile配置文件)
  • @Configuration注解类上的@PropertySource
  • 通过SpringApplication.setDefaultPerties指定的默认属性

自动配置原理

所有配置文件用到的配置可以在这里找到通用应用程序属性
1、SpringBoot启动的时候加载主配置类,开启自动配置功能 ==@EnableAutoConfiguration==

  • EnableAutoConfiguration作用就是利用AutoConfigurationImportSelector的selectImports进行自动装配
  • selectImports里面对选择的配置进行装配:List configurations = getCandidateConfigurations(annotationMetadata,attributes);这句话就是获取候选的配置然后以configurations的形式返回
    • List configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
      作用是扫描所有jar类路径下的META-INF/Spring.factories,把扫描到的文件内容包装成properties对象,从prpperties中获取到EnableAutoConfiguration.class类(类名)对应的值,把他们添加到容器
  • ==EnableAutoConfiguration就是将类路径下META-INF/spring.factories里面配置的所有EnableAutoConfiguration的值加入到容器中==
    每一个这样的xxxAutoConfiguration类都是容器中的一个组件,都加入到容器中;用他们来做自动配置

2、每一个自动配置类进行自动配置功能

3、 以HttpEncodingAutoConfiguration为例解释自动配置功能

@Configuration //表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件
@EnableConfigurationProperties(HttpEncodingProperties.class) //启用指定类的ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来了,并且把HttpEncodingProperties加入到ioc容器中
@ConditionalOnWebApplication//spring底层有一个@Conditional注解。作用是根据不同的条件,如果满足指定的条件,那么整个配置类里面的配置就会生效,这个注解的意思是判断这个应哟共是否是web应用,如果是那么当前配置类生效
@ConditionalOnClass(CharacterEncodingFilter.class)//判断当前项目由没有CharacterEncodingFilter这个类,这个类是Springmvc中解决乱码问题的拦截器
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)//判断配置文件中国是否存在某个配置,spring.http.encoding,matchIfMissing如果不存在,判断也是成立的,
//
public class HttpEncodingAutoConfiguration {

//已经和SpringBoot的配置文件映射
private final HttpEncodingProperties properties;

//只有一个有参构造器的情况下,参数的值就会从容器中拿到
public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
this.properties = properties;
}

@Bean//给容器中添加一个组件,这个组件的某些值需要从properties中获取
@ConditionalOnMissingBean(CharacterEncodingFilter.class)
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name()); // 这里面就是取得配置文件中的值
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter;
}

所有在配置文件能配置的属性都是在xxxProperties类中封装这;配置文件中能配置什么就可以参照某个功能对应的这个属性类

@ConfigurationProperties(prefix = "spring.http.encoding") //从配置文件中获取指定的值和bean的属性进行绑定
public class HttpEncodingProperties {

public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

对应的properties里面的属性

#我们能配置的属性都是来源于这个功能的
spring.http.encoding.enabled=true
spring.http.encoding.charset = utf-8
spring.http.encoding.force = true
  • @Configuration //表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件
  • @EnableConfigurationProperties(HttpEncodingProperties.class) //启用指定类的ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来了
    • HttpEncodingProperties类里面实现的ConfigurationProperties注解,直接解析spring.http.encoding配置
  • @ConditionalOnWebApplication //spring底层有一个@Conditional注解。作用是根据不同的条件,如果满足指定的条件,那么整个配置类里面的配置就会生效,这个注解的意思是判断这个应哟共是否是web应用,如果是那么当前配置类生效
  • @ConditionalOnClass(CharacterEncodingFilter.class)//判断当前项目由没有CharacterEncodingFilter这个类,这个类是Springmvc中解决乱码问题的拦截器
  • @ConditionalOnProperty(prefix = “spring.http.encoding”, value = “enabled”, matchIfMissing = true)//判断配置文件中国是否存在某个配置,spring.http.encoding,matchIfMissing如果不存在,判断也是成立的,即使我们配置文件不配置spring.http.encoding= true 也能默认生效
  • @Bean//给容器中添加一个组件,这个组件的某些值需要从properties中获取

根据当前不同的条件判断,决定这个配置类是否生效,一旦这个配置类生效,这话配置类就会给容器中添加各种组件,这些组件的属性都是从对应的properties中获取的,这些类里面的每个属性又是和配置文件绑定的

Springboot精髓:

  • SpringBoot启动会加载大量的自动配置类
  • 我们看我们需要的功能有没有SpringBoot默认写好的自动配置类
  • 我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件有,那么我们就不需要再来配置了)
  • 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性,我们就可以在配置文件中指定这些属性的值
    XXXAutoConfigurartion:自动配置类;
    给容器中添加组件;
    XXXProperties:封装配置文件中的相关属性;

一些细节

  • @Conditional派生注解(Spring中有这个注解,属于原生Spring的注解)
    • 作用:必须是@Conditional指定的条件才能成立,才能给容器中添加组件,配置里面的所有内容才能生效;
    • SpringBoot中对这个注解做了很多扩展,
@Conditional扩展注解 作用(判断是否满足当前指定条件)
@ConditionalOnJava 系统的java版本是否符合要求
@ConditionalOnBean 容器中存在指定Bean;
@ConditionalOnMissingBean 容器中不存在指定Bean;
@ConditionalOnExpression 满足SpEL表达式指定
@ConditionalOnClass 系统中有指定的类
@ConditionalOnMissingClass 系统中没有指定的类
@ConditionalOnSingleCandidate 容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty 系统中指定的属性是否有指定的值
@ConditionalOnResource 类路径下是否存在指定资源文件
@ConditionalOnWebApplication 当前是web环境
@ConditionalOnNotWebApplication 当前不是web环境
@ConditionalOnJndi JNDI存在指定项

自动配置类一般在一定条件下才能生效;
我们怎么知道哪些自动配置类生效;
我们可以通过在配置文件中启用 debug=true属性;来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效;

文章作者: zenshin
文章链接: https://zlh.giserhub.com/2020/03/28/springboot/config/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 zenshin's blog
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论