前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >SpringBoot如何加载外部自定义的配置文件

SpringBoot如何加载外部自定义的配置文件

原创
作者头像
半月无霜
发布2025-01-08 00:04:34
发布2025-01-08 00:04:34
30700
代码可运行
举报
文章被收录于专栏:半月无霜半月无霜
运行总次数:0
代码可运行

一、前言

你是否有想过,NacosConsul是如何成为配置中心的,Spring是如何读取到这些外部的配置文件的呢?

我之前就有这个疑问,直到上次看了一篇博客,解决MyBatisPlus的数据源加密放在Nacos的问题

在文档中,它获取了一个bean,就是NacosPropertySourceLocator,在这段代码中,获取到Nacos上的数据源密文,然后进行解密,最后组装返回了PropertySource对象。之后就能成功获取到解密后的数据源了,Mybatis也就能正常使用了。

而在NacosPropertySourceLocator其中,我发现了它实现了PropertySourceLocator,在一番摸索之下,我明白了,这就是Spring加载外部配置文件的关键。

那么本文,将会实现这个接口,完成加载外部自定义配置文件到服务之中,我们就简单点,用本地的一个文件来代替。

二、源码

按照惯例,先看看这个接口,里面定义了什么方法

代码语言:java
复制
package org.springframework.cloud.bootstrap.config;
​
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
​
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
​
public interface PropertySourceLocator {
​
    PropertySource<?> locate(Environment environment);
​
    default Collection<PropertySource<?>> locateCollection(Environment environment) {
        return locateCollection(this, environment);
    }
​
    static Collection<PropertySource<?>> locateCollection(PropertySourceLocator locator, Environment environment) {
        PropertySource<?> propertySource = locator.locate(environment);
        if (propertySource == null) {
            return Collections.emptyList();
        }
        if (CompositePropertySource.class.isInstance(propertySource)) {
            Collection<PropertySource<?>> sources = ((CompositePropertySource) propertySource).getPropertySources();
            List<PropertySource<?>> filteredSources = new ArrayList<>();
            for (PropertySource<?> p : sources) {
                if (p != null) {
                    filteredSources.add(p);
                }
            }
            return filteredSources;
        }
        else {
            return Arrays.asList(propertySource);
        }
    }
​
}

一个方法locate(),返回了PropertySource,另一个是默认的方法可以返回PropertySource的集合

源码非常简单,下面我们去实现一下这个接口

三、代码

那么我们只需要实现这个方法就好了

代码语言:java
复制
package com.banmoon.business.config;
​
import cn.hutool.core.io.resource.ResourceUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.yaml.snakeyaml.Yaml;
​
import java.io.BufferedReader;
import java.util.Map;
​
@Slf4j
@Order(0)
@Configuration
public class CustomPropertySourceLocatorConfig implements PropertySourceLocator {
​
    @Override
    @SneakyThrows
    public PropertySource<?> locate(Environment environment) {
        BufferedReader reader = ResourceUtil.getUtf8Reader("D:\\test.yaml");
        Yaml yaml = new Yaml();
        Map<String, Object> yamlMap = yaml.loadAs(reader, Map.class);
        return new MapPropertySource("customYaml", yamlMap);
    }
}

非常简单,就是读取yaml文件,然后生成一个PropertySource返回出去

现在,我们准备一下test.yaml,我们将它放到D盘下,里面就简单放两个参数

代码语言:javascript
代码运行次数:0
运行
复制
user:
  name: 半月无霜
  age: 18

接下来,就是编码了,我们搞简单点,就直接在Main启动类上添加读取上面文件的配置信息

代码语言:java
复制
package com.banmoon;
​
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.EnableScheduling;
​
import java.util.Map;
​
@Slf4j
@EnableScheduling
@SpringBootApplication
public class WebBaseMain {
​
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(WebBaseMain.class, args);
        Environment environment = context.getBean(Environment.class);
        Map<String, Object> map = environment.getProperty("user", Map.class);
        log.info("user: {}", map);
    }
​
}

但我执行后,没有效果?怎么回事,我寻找了半天,

原来就算添加了@Configuration,将此类注册成为一个配置bean,但由于这里面没有什么bean需要注册的,所以也就是相当于一个空壳。所以这边还需要添加SPISpring将其自动注册成为一个配置类,就能去处理了。

spring.factories文件上添加

image-20250107234848405
image-20250107234848405
代码语言:yaml
复制
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
  com.banmoon.business.config.CustomPropertySourceLocatorConfig

只要加上了,原本CustomPropertySourceLocatorConfig类上的@Configuration也不需要了

此时此刻,我们再启动服务,查看效果

image-20250107235056849
image-20250107235056849

四、最后

好的,由于时间紧迫,上面的代码还是有点小瑕疵;后续想想如何改进一下

希望可以通过本篇文章,对PropertySourceLocator这个接口有一个初步的认知,

再次说明,必须要在spring.factories添加类,加注解是没有用的,这是springSPI机制

后面看情况会出篇这样的文章,看看spring是如何通过这种方式加载bean

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言
  • 二、源码
  • 三、代码
  • 四、最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档