[Java] Spring项目通过git统一管理配置文件

技术栈:springboot2.0,docker,k8s

 

在做java的spring项目开发,少不了涉及到不同环境的配置问题。一般情况下,生产的配置都不会直接放到项目里面的,这就涉及如何管理好生产配置的问题。

本文介绍通过git来统一管理项目的配置文件(特别是使用到微服务),以方便日常开发部署

 

步骤一 源码实现

首先,你得有一个所有微服务都用到的公共包

这里用到最关键的知识点就是Spring SPI。如对想深入了解,建议先google一下

源码: src/main/resources/META-INF/spring.factories

# Bootstrap Configuration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.ppwang.lib.common.config.file.LibBusinessConfigBootstrapConfiguration

 

源码: src/main/java/com/ppwang/lib/common/config/file/LibBusinessConfigBootstrapConfiguration.java

package com.ppwang.lib.common.config.file;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * {@code LibBusinessConfigBootstrapConfiguration} 描述内容
 *
 */
@Configuration("com.ppwang.lib.common.config.file.LibBusinessConfigBootstrapConfiguration")
@ConditionalOnProperty(
        prefix = "pp-lib-business.common.config.file",
        value = "libBusinessConfigBootstrapConfiguration.enabled",
        havingValue = "true",
        matchIfMissing = true
)
public class LibBusinessConfigBootstrapConfiguration {

    @Bean
    public LibBusinessPropertySourceLocator libBusinessPropertySourceLocator() {
        return new LibBusinessPropertySourceLocator();
    }
}

 

 

 

源码: src/main/java/com/ppwang/lib/common/config/file/LibBusinessPropertySourceLocator.java

package com.ppwang.lib.common.config.file;

import com.ppwang.lib.common.util.LogUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * {@code LibBusinessPropertySourceLocator} 描述内容
 *
 */
@Order(-1)
@Slf4j
public class LibBusinessPropertySourceLocator implements PropertySourceLocator {

    @Override
    public PropertySource<?> locate(Environment environment) {
        if (!(environment instanceof ConfigurableEnvironment)) {
            return null;
        } else {
            ConfigurableEnvironment env = (ConfigurableEnvironment)environment;
            String configFolderPath = env.getProperty(
                    "pp-lib-business.common.config.file.libBusinessPropertySourceLocator.pea-config-center-java",
                    String.format("/opt/pea-config-center-java/%s", env.getProperty("spring.application.name"))
            );

            CompositePropertySource composite = new CompositePropertySource("pea-config-center-java");
            try {
                Files
                        .list(Paths.get(configFolderPath))
                        .filter(Files::isRegularFile)
                        .forEach(file -> assembleCompositePropertySource(composite, file));
            } catch (Exception e) {
                log.info("{}. Lib business config folder does not exist.", LogUtils.fileInfoStr());
                return null;
            }

            return composite;
        }
    }

    private void assembleCompositePropertySource(CompositePropertySource composite, Path configFolderFilePath) {
        try {
            File configFolderFile = configFolderFilePath.toFile();
            LibBusinessPropertySource libBusinessPropertySource = new LibBusinessPropertySource(configFolderFile.getName(), configFolderFile);
            libBusinessPropertySource.init();
            composite.addPropertySource(libBusinessPropertySource);
        } catch (Exception e) {
            log.info("{}. {}, Lib business config folder file load failed.", LogUtils.fileInfoStr(), configFolderFilePath.getFileName(), e);
        }
    }

}

 

 

 

源码: src/main/java/com/ppwang/lib/common/config/file/LibBusinessPropertySource.java 

package com.ppwang.lib.common.config.file;

import com.ppwang.lib.common.util.LogUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.cloud.consul.config.encrypt.EncryptConfig;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * {@code LibBusinessPropertySource} 描述内容
 *
 */
@Slf4j
public class LibBusinessPropertySource extends EnumerablePropertySource<File> {

    private final Map<String, Object> properties = new LinkedHashMap();

    public LibBusinessPropertySource(String name, File source) {
        super(name, source);
    }

    public void init() {
        YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
        try {
            List<PropertySource<?>> loads = loader.load("pea-config-center-java", new FileSystemResource(this.source));
            if (CollectionUtils.isEmpty(loads)) {
                return;
            }
            PropertySource<?> propertySource = loads.get(0);
            Map<String, Object> sourceMap = (Map<String, Object>) propertySource.getSource();

            Iterator<Map.Entry<String, Object>> iterator = sourceMap.entrySet().iterator();
            if (EncryptConfig.getEnabled()) {
                while (iterator.hasNext()) {
                    Map.Entry<String, Object> entry = iterator.next();
                    if (EncryptConfig.needDecrypt(entry.getValue())) {
                        if (log.isTraceEnabled()) {
                            log.debug(
                                    "[pea-config-center-java] Need Decrypt {} > {}: {}",
                                    entry.getKey(), entry.getKey(), entry.getValue());
                        }

                        String decryptedValue = EncryptConfig.getProvider().decrypt(
                                EncryptConfig.realContent(entry.getValue()), EncryptConfig.getPassword()
                        );
                        this.properties.put(entry.getKey(), decryptedValue);
                    } else {
                        this.properties.put(entry.getKey(), entry.getValue());
                    }
                }
            } else {
                while(iterator.hasNext()) {
                    Map.Entry<String, Object> entry = iterator.next();
                    this.properties.put(entry.getKey(), entry.getValue());
                }
            }
        } catch (Exception e) {
            log.info(
                    "{}. Failed to load pea-config-center-java file. {}, {}",
                    LogUtils.fileInfoStr(),
                    this.source.getPath(),
                    this.source.getName(),
                    e
            );
        }
    }

    @Override
    public String[] getPropertyNames() {
        Set<String> strings = this.properties.keySet();
        return strings.toArray(new String[0]);
    }

    @Override
    public Object getProperty(String name) {
        return this.properties.get(name);
    }
}

 

 

 

步骤二,运维层面

我们的配置通过git管理之后,在打包docker镜像的时候,可从git上拉取配置,然后复制到镜像里约定好的目录下。比如,这里是/opt/pea-config-center-java/${spring.application.name}。注意这里${spring.application.name}指的是项目名

 

其他细节就不用多说了,按以上操作就可实现通过git来统一管理配置项

 

Have fun with java & spring!

 

posted @ 2022-09-24 16:24  DavidHHuan  阅读(348)  评论(0编辑  收藏  举报