小计02:SpringBoot自定义属性文件读取

266 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情

和玩得来的人在一起玩才叫玩,和玩不来的人在一起玩,那种感觉就像加班!

0.SpringBoot配置文件类型和作用

SpringBoot是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用application.properties或者application.yml(application.yaml)进行配置。

SpringBoot默认会从Resources目录下加载application.properties或application.yml(application.yaml)文件

其中,application.properties文件是键值对类型的文件,之前一直在使用,所以此处不在对properties文件的格式进行阐述。除了properties文件外,SpringBoot还可以使用yml文件进行配置,下面对yml文件进行讲解。

YML文件格式是YAML (YAML Aint Markup Language)编写的文件格式,YAML是一种直观的能够被电脑识别的的数据数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,比如: C/C++, Ruby, Python, Java, Perl, C#, PHP等。YML文件是以数据为核心的,比传统的xml方式更加简洁。

YML文件的扩展名可以使用.yml或者.yaml。

获取方式:

laker:
  username: laker
  • @Value方式
    @Component
    public class LakerBean {
        @Value("${laker.username}")
        private String username;
    }
    
  • @ConfigurationProperties注解(建议)
    @Configuration 
    @Data
    @ConfigurationProperties(prefix = "laker") 
    public class TestConfig {
       
        private String username;
        private String password;
    }
    @Component
    public class LakerBean {
       
        @Autowired
        TestConfig testConfig ;
    }
    
    
  • Environment接口
    @Component
    public class LakerBean {
       
        @Autowired
        Environment env;
        ...
        env.getProperty("laker.username")
    }
    

1.加载一个properties文件转换为对象

1.1 配置文件-blog.properties

com.chenheng.blog.name=胖先森
com.chenheng.blog.title=Spring Boot学习教程
com.chenheng.blog.desc=${com.chenheng.blog.name}正在努力写《${com.chenheng.blog.title}》
# 随机字符串
com.chenheng.blog.value=${random.value}
# 随机int
com.chenheng.blog.number=${random.int}
# 随机long
com.chenheng.blog.bignumber=${random.long}
# 10以内的随机数
com.chenheng.blog.test1=${random.int(10)}
# 10-20的随机数
com.chenheng.blog.test2=${random.int[10,20]}

1.2 Java类(Blog2Properties)

使用注解@ConfigurationProperties映射对象(配置文件与对象绑定) 通过注解@ConfigurationProperties(prefix="配置文件中的key的前缀,可以使properties文件也可以是yml文件")可以将配置文件中的配置自动与实体进行映射(这个注解能作用在类上也能作用在方法上)

注意:使用@ConfigurationProperties方式可以进行配置文件与实体字段的自动映射,但需要字段必须提供set方法才可以,而使用@Value注解修饰的字段不需要提供set方法

package com.chenheng.properties;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

@PropertySource(value={"classpath:config/blog.properties"})
@ConfigurationProperties(prefix = "com.chenheng.blog")
@Component
@Data
public class Blog2Properties {
    private String name;
    private String title;
    private String desc;
    private String value;
    private String number;
    private String bignumber;
    private String test1;
    private String test2;
}

1.3 运行测试

package com.chenheng;

import com.chenheng.properties.Blog2Properties;
import com.chenheng.properties.BlogProperties;
import com.chenheng.properties.PersonProperties;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class SpringBootTest01 {
    @Autowired
    private Blog2Properties blog2Properties;
    @Test
    void testProperties02(){
        System.out.println(blog2Properties);
    }
}

2.加载一个properties文件转换为List和Map

2.1 配置文件-cityCode.properties

#List properties
com.city.code.list[0]=www
com.city.code.list[1]=localhost
com.city.code.list[2]=wuhan
com.city.code.list[3]=tianjin
#Map Properties
com.city.code.map.www=4201
com.city.code.map.wuhan=4201
com.city.code.map.tianjin=1200

2.2 Java类(CityCodeProperties)

package com.chenheng.properties;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@PropertySource(value={"classpath:config/cityCode.properties"})
@ConfigurationProperties(prefix = "com.city.code")
@Component
@Data
public class CityCodeProperties {
    private List<String> list = new ArrayList<>();

    private Map<String, String> map = new HashMap<>();
}

2.3 运行测试

package com.chenheng;

import com.chenheng.properties.Blog2Properties;
import com.chenheng.properties.BlogProperties;
import com.chenheng.properties.CityCodeProperties;
import com.chenheng.properties.PersonProperties;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;
import java.util.Map;

@SpringBootTest
public class SpringBootTest01 {
    @Autowired
    private CityCodeProperties cityCodeProperties;
    @Test
    void testCityCodeProperties(){
        List<String> list = cityCodeProperties.getList();
        Map<String, String> map = cityCodeProperties.getMap();
        System.out.println(list + "->" + map);
    }
}

参考

list: topic1,topic2,topic3
maps: "{key1: 'value1', key2: 'value2'}
maps2: "{key1: '[value1,value2]', key2: '[value1,value2]'}
@Value("#{'${list}'.split(',')}")
private List<String> list;
 
@Value("#{${maps}}")  
private Map<String,String> maps;
 
@Value("#{${maps}}")  
private Map<String,List<String>> maps;

3.@PropertySource 注解实现读取 yml 文件

3.1 配置文件-person.yml

person:
  name: lucy
  age: 16
  addr: 北京
  books: [java,kafka,netty]
  course-map-teacher: {key1: v1,key2: v2}
  dog:
    name: ${person.name}
    age: ${random.int(5)} #表达式

3.2 PersonProperties类

package com.chenheng.properties;

import factory.MyPropertySourceFactory;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

/**
 * @PropertySource 默认的无法读取yml文件,需要写一个类即MyPropertySourceFactory
 * https://juejin.cn/post/6844903768308334606
 */
@PropertySource(value={"classpath:config/person.yml"},encoding = "utf-8",factory = MyPropertySourceFactory.class)
@ConfigurationProperties(prefix = "person")
@Component
@Data
public class PersonProperties {
    private String name;

    private int age;

    private String addr;

    private List<String> books;

    private Map<String, String> courseMapTeacher;

    private Dog dog;
}

3.3 MyPropertySourceFactory 类

在实际的开发中使用 @PropertySource 注解无法加载 yml 配置文件问题,需要继承DefaultPropertySourceFactory类,重写createPropertySource方法

package factory;

import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.io.support.EncodedResource;

import java.io.IOException;
import java.util.List;

public class MyPropertySourceFactory extends DefaultPropertySourceFactory {
    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
        if (resource == null){
            return super.createPropertySource(name, resource);
        }
        List<PropertySource<?>> sources = new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource());
        return sources.get(0);
    }
}

3.4 运行测试

package com.chenheng;

import com.chenheng.properties.Blog2Properties;
import com.chenheng.properties.BlogProperties;
import com.chenheng.properties.CityCodeProperties;
import com.chenheng.properties.PersonProperties;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;
import java.util.Map;

@SpringBootTest
public class SpringBootTest01 {
    @Autowired
    private PersonProperties personProperties;
    @Test
    void testPersonProperties(){
        System.out.println(personProperties);
    }
}

参考文档:

www.w3cjava.com/technical-a…