Springboot中读取配置文件的n种方式

SpringBoot项目种获取配置信息的N种方法

一、通过@Value注解获取

在任意Bean对象种通过@Value注解可以获取到对应的配置信息,代码样例如下:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Properties;

@Configuration
public class ClassPathProp {
    @Value("${prop.value.key_1}")
    private String valueKey_1;
    @Value("${prop.value.key_2}")
    private String valueKey_2;
    
    @Bean(name = "propertiesByValue")
    public Properties getPropertiesByValue() {
        Properties res = new Properties();
        res.put("prop.value.key_1", valueKey_1);
        res.put("prop.value.key_2", valueKey_2);
        return res;
    }
}

优缺点分析:

  • 优点:只要是Spring管理的Bean对象都可以获取到配置信息
  • 缺点:1. 需要知道配置项的全名;2. 对于非Spring管理的对象,无法使用;3. 只能获取到Spring管理的配置信息

二、通过Environment对象获取

在任务Bean对象中注入Environment对象后,通过Environment对象提供的getProperty(String name)方法可以获取到对应的配置信息,代码样例:

@Configuration
public class ClassPathProp {
    @Autowired
    private AbstractEnvironment env;
    
	@Bean(name = "propertiesByEnv")
    public Properties getPropertiesByEnv() {
        Properties res = new Properties();
        final String key_1="prop.env.envKey.name";
        final String key_2="prop.env.envKey.val";
        res.put(key_1,this.env.getProperty(key_1));
        res.put(key_2,this.env.getProperty(key_2));
        return res;
    }
}

优缺点分析:

  • 优点:1. 只要是Spring管理的Bean对象都可以获取到配置信息;2.只要是Spring的配置信息都能通过名称获取到;3. 只需要创建一个全局变量
  • 缺点:1. 需要知道配置项的全名;2. 对于非Spring管理的对象,无法使用;3. 只能获取到Spring管理的配置信息

三、通过@ConfigurationProperties注解获取

创建一个pojo对象,使用@ConfigurationProperties注解说明配置项的前缀,使用这种方法必须保证类的属性名和配置文件中的配置项名称一致,驼峰命名xxxXxx对应配置文件中的xxx-xxx,对于多层属性,需要创建静态内部类获取配置信息。代码示例:

package top.sunyog.spring.notes.prop;

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

import java.util.Properties;

@Component
@ConfigurationProperties(prefix = "prop.app")
public class AppProperties {
    private String testKey;
    private String dbKey;

    private AppDatasource appDatasource;

    public AppDatasource getAppDatasource() {
        return appDatasource;
    }

    public void setAppDatasource(AppDatasource appDatasource) {
        this.appDatasource = appDatasource;
    }

    public String getTestKey() {
        return testKey;
    }

    public void setTestKey(String testKey) {
        this.testKey = testKey;
    }

    public String getDbKey() {
        return dbKey;
    }

    public void setDbKey(String dbKey) {
        this.dbKey = dbKey;
    }

    /**
     * 多层配置信息,需要添加静态内部类,静态内部类实现getter,setter方法
     */
    public static class AppDatasource{
        private String dbType;
        private Integer dbCount;

        public String getDbType() {
            return dbType;
        }

        public void setDbType(String dbType) {
            this.dbType = dbType;
        }

        public Integer getDbCount() {
            return dbCount;
        }

        public void setDbCount(Integer dbCount) {
            this.dbCount = dbCount;
        }
    }

    public Properties getProperties(){
        Properties res = new Properties();
        res.put("testKey",this.testKey);
        res.put("dbKey",this.dbKey);
        res.put("appDatasource.dbCount",this.appDatasource.dbCount);
        res.put("appDatasource.dbType",this.appDatasource.dbType);
        return res;
    }
}

优缺点分析:

  • 优点:方便管理(能够将同一类的配置信息保存到同一个对象中)
  • 缺点:1.需要知道配置项的全名才能获取到配置信息;2.只能获取到Spring管理的配置信息

四、通过@PropertySource注解获取(方法三的变种)

通过@PropertySource注解说明配置文件的路径,可以获取到对应配置文件中的配置信息,代码样例:

package top.sunyog.spring.notes.prop;

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

import java.util.Properties;

@Component
@PropertySource(value = "classpath:config/source.properties",encoding = "UTF-8",ignoreResourceNotFound = true)
@ConfigurationProperties(prefix = "config")
public class SourceProperties {
    private String username;
    private String password;
    private String url;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public Properties getProperties(){
        Properties res = new Properties();
        res.put("username",this.getUsername());
        res.put("password",this.password);
        res.put("url",this.url);
        return res;
    }
}

优缺点分析:

  • 优点:可以获取到任意配置文件中自定义的配置信息
  • 缺点:1.需要设定文件路径;2.需要知道配置项的全名

五、通过PropertiesFactoryBean对象获取配置信息

创建一个PropertiesFactoryBean对象,设定好资源位置后,通过getObject()方法可以获取到该位置下的所有配置信息,代码样例:

@Configuration
public class ClassPathProp {
    private final String PROPERTIES_PATH = "application.properties";
	
    @Bean(name = "propertiesByPath")
    public Properties getPropertiesByPath() throws IOException {
        PropertiesFactoryBean propFactoryBean = new PropertiesFactoryBean();
        propFactoryBean.setLocation(new ClassPathResource(this.PROPERTIES_PATH));
        propFactoryBean.afterPropertiesSet();
        return propFactoryBean.getObject();
    }

优缺点分析:

  • 优点:只需知道配置文件路径,不需要配置项的名称即可获取到
  • 缺点:1. 需要知道配置文件的路径;2. 只能获取到本地配置信息

六、通过输入流直接读取配置文件

jdk提供了Properties对象,可以通过输入流直接读取配置文件,代码样例:

@Configuration
public class ClassPathProp {
	@Bean(name = "propertiesByStream")
    public Properties getPropertiesByStream() throws IOException {
        Properties res = new Properties();
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("config/setting.properties");
        InputStreamReader reader = new InputStreamReader(inputStream);
        res.load(reader);
        reader.close();
        inputStream.close();
        return res;
    }
}

优缺点分析:

  • 优点:只需知道配置文件路径,不需要配置项的名称即可获取到
  • 缺点:1. 需要知道配置文件的路径;2. 只能获取到本地配置信息

七、通过EnumerablePropertySource对象获取到所有配置项

AbstractEnvironment对象中存在一个getPropertySources()方法,可以用来获取所有属性资源,其中EnumerablePropertySource类用来存储所有配置属性,可通过它的.getPropertyNames()方法获取所有配置项的名称。代码样例:

@Configuration
public class ClassPathProp {
    @Bean(name = "propertiesAll")
    public Properties getAllPropertiesByEnv() {
        Properties res = new Properties();
        MutablePropertySources sources = env.getPropertySources();
        for (PropertySource<?> source : sources) {
            if (source instanceof EnumerablePropertySource) {
                String[] names = ((EnumerablePropertySource<?>) source).getPropertyNames();
                for (String name : names) {
                    res.put(name, source.getProperty(name));
                }
            }
        }
        return res;
    }
}

优缺点分析:

  • 优点:可以获取到Spring程序中的所有配置信息,不需要知道配置项名称
  • 缺点:应用程序中的配置信息数量太多,需要按条件筛选后再使用

样例代码对应的配置文件如下:

  1. application.properties文件
server.port=18080
spring.application.name=notes
prop.value.key_1=key_1
prop.value.key_2=key_2
prop.env.envKey.name=envKey
prop.env.envKey.val=1000
prop.app.testKey=junit
prop.app.dbKey=mysql 5.8
prop.app.app-datasource.db-type=mysql
prop.app.app-datasource.db-count=3
  1. config/setting.properties文件
setting.function.name=method
setting.function.param=json
setting.field.name=pro
setting.field.val=str
  1. config/source.properties文件
config.username=root
config.password=abcd@
config.url=https://test.top

测试打印配置内容相关代码:

package top.sunyog.spring.notes.auto;

import org.springframework.beans.BeansException;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import top.sunyog.spring.notes.prop.AppProperties;
import top.sunyog.spring.notes.prop.SourceProperties;

import java.text.MessageFormat;
import java.util.Map;
import java.util.Properties;

/*
 * 项目启动后立即执行该代码
 */
@Component
public class PropertiesInfoRunner implements ApplicationRunner, ApplicationContextAware {
    private ApplicationContext context;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        //测试使用Environment对象读取所有配置
        String envAllType = "propertiesAll";
        Object propertiesEnvAll = context.getBean(envAllType);
        this.printProperties(envAllType,((Properties) propertiesEnvAll));

        //测试使用PropertyFactoryBean对象读取配置
        String pathType = "propertiesByPath";
        Object propertiesByPath = context.getBean(pathType);
        this.printProperties(pathType,((Properties) propertiesByPath));

        //测试使用@Value注解读取配置
        String valueType = "propertiesByValue";
        Object propertiesByValue = context.getBean(valueType);
        this.printProperties(valueType,((Properties) propertiesByValue));

        //测试使用Environment对象读取配置
        String envType = "propertiesByEnv";
        Object propertiesByEnv = context.getBean(envType);
        this.printProperties(envType,((Properties) propertiesByEnv));

        //测试使用@ConfigurationProperties注解读取配置
        String appType="propertiesApp";
        AppProperties appProperty = context.getBean(AppProperties.class);
        this.printProperties(appType,appProperty.getProperties());

        //测试使用@PropertySource注解读取配置
        String sourceType="propertiesSource";
        SourceProperties sourceProperty = context.getBean(SourceProperties.class);
        this.printProperties(sourceType,sourceProperty.getProperties());

        //测试jdk原生方法读取配置
        String jdkType="propertiesByStream";
        Object propertiesByStream = context.getBean(jdkType);
        this.printProperties(jdkType, ((Properties) propertiesByStream));
    }

    private void printProperties(String type,Properties properties) {
        //左{需要使用单引号包裹,否则格式化时报错
        final String msgFormat="{0}:=====>'{'key = {1}, value = {2}}";
        for (Map.Entry<Object, Object> entry : properties.entrySet()) {
            System.out.println(MessageFormat.format(msgFormat,type,entry.getKey(),entry.getValue()));
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }
}

打印内容如下:

Connected to the target VM, address: '127.0.0.1:13426', transport: 'socket'

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::       (v2.3.12.RELEASE)

2022-07-28 14:23:24.089  INFO 5040 --- [           main] t.s.spring.notes.SpringNotesApplication  : Starting SpringNotesApplication on DESKTOP-MVSU4U6 with PID 5040 (D:\Activities\code\springboot\springboot-notes\target\classes started by Myste in D:\Activities\code\springboot)
2022-07-28 14:23:24.091  INFO 5040 --- [           main] t.s.spring.notes.SpringNotesApplication  : No active profile set, falling back to default profiles: default
2022-07-28 14:23:24.481  INFO 5040 --- [           main] t.s.spring.notes.SpringNotesApplication  : Started SpringNotesApplication in 0.651 seconds (JVM running for 0.957)
此处省略一堆。。。
propertiesAll:=====>{key = intellij.debug.agent, value = true}
propertiesAll:=====>{key = DriverData, value = 简略。。。}
propertiesAll:=====>{key = IDEA_INITIAL_DIRECTORY, value = 简略。。。}
propertiesByPath:=====>{key = prop.app.testKey, value = junit}
propertiesByPath:=====>{key = prop.app.app-datasource.db-type, value = mysql}
propertiesByPath:=====>{key = server.port, value = 18080}
propertiesByPath:=====>{key = prop.app.dbKey, value = mysql 5.8}
propertiesByPath:=====>{key = prop.env.envKey.val, value = 1000}
propertiesByPath:=====>{key = prop.value.key_2, value = key_2}
propertiesByPath:=====>{key = prop.value.key_1, value = key_1}
propertiesByPath:=====>{key = prop.app.app-datasource.db-count, value = 3}
propertiesByPath:=====>{key = spring.application.name, value = notes}
propertiesByPath:=====>{key = prop.env.envKey.name, value = envKey}
propertiesByValue:=====>{key = prop.value.key_2, value = key_2}
propertiesByValue:=====>{key = prop.value.key_1, value = key_1}
propertiesByEnv:=====>{key = prop.env.envKey.name, value = envKey}
propertiesByEnv:=====>{key = prop.env.envKey.val, value = 1000}
propertiesApp:=====>{key = appDatasource.dbType, value = mysql}
propertiesApp:=====>{key = appDatasource.dbCount, value = 3}
propertiesApp:=====>{key = dbKey, value = mysql 5.8}
propertiesApp:=====>{key = testKey, value = junit}
propertiesSource:=====>{key = url, value = https://test.top}
propertiesSource:=====>{key = password, value = abcd@}
propertiesSource:=====>{key = username, value = root}
propertiesByStream:=====>{key = setting.function.param, value = json}
propertiesByStream:=====>{key = setting.field.val, value = str}
propertiesByStream:=====>{key = setting.function.name, value = method}
propertiesByStream:=====>{key = setting.field.name, value = pro}
Disconnected from the target VM, address: '127.0.0.1:13426', transport: 'socket'

Process finished with exit code 0


项目目录结构如下:

Springboot中读取配置文件的n种方式_第1张图片

你可能感兴趣的:(Spring技术,Java基础,JVM,spring,boot,spring,java)