项目启动时对yml文件的修改(nacos启动地址切换样例)

41 篇文章 0 订阅
1 篇文章 0 订阅

JYaml 方式

这种方式我简单用了一下就放弃了,主要是他会直接修改yaml 文件内容,不是修改class 文件
下面有修改class 文件的方式

附上yml文件的读取:https://www.cnblogs.com/mysgk/p/9790801.html
参考:https://blog.csdn.net/m0_37739193/article/details/78690680

jyaml 方式代码
注意:
1、接收文件实际用时最好不要使用map,至于问什么(你用了就知道了)!
2、特别注意这种方式是直接修改的yaml文件内容,不是class 文件,改了就真是改了,提前备份下。

		pom加一下
		<dependency>
            <groupId>org.jyaml</groupId>
            <artifactId>jyaml</artifactId>
            <version>1.3</version>
        </dependency>



		/**
        * 获取文件内容
        */
		//获取项目名称
		String path = System.getProperty("user.dir");
		//要读取的文件路径
        File dumpFile = new File(path + "/qiun-service/bbjh-value-added/src/main/resources/bootstrap.yml");
        //将读取的yaml转换成map
        HashMap hashMap = Yaml.loadType(dumpFile, HashMap.class);
        
        /**
        * 修改文件
        */
        //流读取要修改的yaml 文件
        YamlEncoder enc = new YamlEncoder(new FileOutputStream(dumpFile));
        //将内容写入读取的yaml文件中
        enc.writeObject(hashMap);
        enc.flush();
        enc.close();

启动前修改yaml 的class 文件(也是我用的方式)

如果只是单纯的需要修改yml 文件,光看那个工具类就可以了
场景:需要在项目启动时修改yaml 文件中配置,项目使用修改的参数启动。

首先看一下yml 文件

spring:
  profiles:
    active: dev
  application:
    name: bbjh-value-added #nacos配置中心的 Data_Id  (xxlJob.yaml)
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848 
        file-extension: yaml #指定配置文件类型为yaml文件
        group: SMS_GROUP

首先来一个工具类先(获取以及修改yaml文件的工具类)

网上找的工具类很好用

@Slf4j
@Component
public class YamlUtils {

	private final static DumperOptions OPTIONS = new DumperOptions();

	static {
		//设置yaml读取方式为块读取
		OPTIONS.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
		OPTIONS.setDefaultScalarStyle(DumperOptions.ScalarStyle.PLAIN);
		OPTIONS.setPrettyFlow(false);
	}

	/**
	 * 将yaml配置文件转化成map
	 * fileName 默认是resources目录下的yaml文件, 如果yaml文件在resources子目录下,需要加上子目录 比如:conf/config.yaml
	 *
	 * @param fileName
	 * @return
	 */
	public Map<String, Object> getYamlToMap(String fileName) {
		LinkedHashMap<String, Object> yamls = new LinkedHashMap<String, Object>();
		Yaml yaml = new Yaml();
		try {
			@Cleanup InputStream in = YamlUtils.class.getClassLoader().getResourceAsStream(fileName);
			yamls = yaml.loadAs(in, LinkedHashMap.class);
		} catch (Exception e) {
			log.error("{} load failed !!!", fileName);
		}
		return yamls;
	}

	/**
	 * key格式:aaa.bbb.ccc
	 * 通过properties的方式获取yaml中的属性值
	 *
	 * @param key
	 * @param yamlMap
	 * @return
	 */
	public Object getValue(String key, Map<String, Object> yamlMap) {
		String[] keys = key.split("[.]");
		Object o = yamlMap.get(keys[0]);
		if (key.contains(".")) {
			if (o instanceof Map) {
				return getValue(key.substring(key.indexOf(".") + 1), (Map<String, Object>) o);
			} else {
				return null;
			}
		} else {
			return o;
		}
	}

	/**
	 * 使用递归的方式设置map中的值,仅适合单一属性
	 * key的格式: "server.port"
	 * server.port=111
	 **/
	public Map<String, Object> setValue(String key, Object value) {
		Map<String, Object> result = new LinkedHashMap<String, Object>();
		String[] keys = key.split("[.]");
		int i = keys.length - 1;
		result.put(keys[i], value);
		if (i > 0) {
			return setValue(key.substring(0, key.lastIndexOf(".")), result);
		}
		return result;
	}

	public Map<String, Object> setValue(Map<String, Object> map, String key, Object value) {

		String[] keys = key.split("\\.");

		int len = keys.length;
		Map temp = map;
		for (int i = 0; i < len - 1; i++) {
			if (temp.containsKey(keys[i])) {
				temp = (Map) temp.get(keys[i]);
			} else {
				return null;
			}
			if (i == len - 2) {
				temp.put(keys[i + 1], value);
			}
		}
		for (int j = 0; j < len - 1; j++) {
			if (j == len - 1) {
				map.put(keys[j], temp);
			}
		}
		return map;
	}


	/**
	 * 修改yaml中属性的值
	 *
	 * @param key      key是properties的方式: aaa.bbb.ccc (key不存在不修改)
	 * @param value    新的属性值 (新属性值和旧属性值一样,不修改)
	 * @param yamlName
	 * @return true 修改成功,false 修改失败。
	 */
	public boolean updateYaml(String key, Object value, String yamlName) {

		Map<String, Object> yamlToMap = this.getYamlToMap(yamlName);
		if (null == yamlToMap) {
			return false;
		}
		Object oldVal = this.getValue(key, yamlToMap);

		//未找到key 不修改
		if (null == oldVal) {
			log.error("{} key is not found", key);
			return false;
		}
		//不是最小节点值,不修改
		if (oldVal instanceof Map) {
			log.error("input key is not last node {}", key);
			return false;
		}

		//新旧值一样 不修改
		if (value.equals(oldVal)) {
			log.info("newVal equals oldVal, newVal: {} , oldVal: {}", value, oldVal);
			return false;
		}

		Yaml yaml = new Yaml(OPTIONS);
		String path = this.getClass().getClassLoader().getResource(yamlName).getPath();
		try {
			Map<String, Object> resultMap = this.setValue(yamlToMap, key, value);
			if (resultMap != null) {
				yaml.dump(this.setValue(yamlToMap, key, value), new FileWriter(path));
				return true;
			} else {
				return false;
			}
		} catch (Exception e) {
			log.error("yaml file update failed !");
			log.error("msg : {} ", e.getMessage());
			log.error("cause : {} ", e.getCause());
		}
		return false;
	}



	/**
	 * 修改yaml中属性的值(就算key为 null也肯定会修改)
	 *
	 * @param key      key是properties的方式: aaa.bbb.ccc (key不存在不修改)
	 * @param value    新的属性值 (新属性值和旧属性值一样,不修改)
	 * @param yamlName
	 * @return true 修改成功,false 修改失败。
	 */
	public boolean updateYamlToNULL(String key, Object value, String yamlName) {

		Map<String, Object> yamlToMap = this.getYamlToMap(yamlName);
		if (null == yamlToMap) {
			return false;
		}
		Object oldVal = this.getValue(key, yamlToMap);
		//不是最小节点值,不修改
		if (oldVal instanceof Map) {
			log.error("input key is not last node {}", key);
			return false;
		}
		Yaml yaml = new Yaml(OPTIONS);
		String path = this.getClass().getClassLoader().getResource(yamlName).getPath();
		try {
			Map<String, Object> resultMap = this.setValue(yamlToMap, key, value);
			if (resultMap != null) {
				yaml.dump(this.setValue(yamlToMap, key, value), new FileWriter(path));
				return true;
			} else {
				return false;
			}
		} catch (Exception e) {
			log.error("yaml file update failed !");
			log.error("msg : {} ", e.getMessage());
			log.error("cause : {} ", e.getCause());
		}
		return false;
	}

	public static void main(String[] args) {

		YamlUtils configs = new YamlUtils();

		Map<String, Object> yamlToMap = configs.getYamlToMap("conf/config.yaml");

		System.out.println(yamlToMap);

		boolean b = configs.updateYaml("sys.cpu.name", "Intel Core i7", "conf/config.yaml");
		System.out.println(b);

		System.out.println(configs.getYamlToMap("conf/config.yaml"));
	}

}

常量文件

public interface AuthConstant {
/**
     * 环境变量dev
     */
    String DEV = "dev";
    /**
     * 环境变量prod
     */
    String PROD = "prod";
    /**
     * 环境变量test
     */
    String TEST = "test";

    /**
     * nacos 的dev 配置
     */
    String NACOS_DEV = "127.0.0.1:8848";

    /**
     * nacos prod 地址
     */
    String NACOS_PROD = "127.0.0.1:8849";

    /**
     * nacos test 地址
     */
    String NACOS_TEST = "127.0.0.1:8844";
    }

在springBoot 项目启动前先执行方法

该方法用于在项目启动前重置你上次修改的内容。
由于我配置的naocs 修改后,每次启动都会先执行我修改的nacos ,在执行修改方法,造成启动读取出错后中断情况。

	
	//读取的文件
	public static final String BOOTSTRAP_YML_URL = "bootstrap.yml";
    /**
     * nacos 地址
     */
    public static final String NACOS_SERVER_ADDR = "spring.cloud.nacos.config.server-addr";
    /**
     * 项目启动的环境
     */
    public static final String ACTIVE_CONFIG = "spring.profiles.active";

	/**
     * 修改nacos 默认
     * 项目初始化前先执行当前参数用于初始化class 文件中的配置
     */
    public void upNacosData(){
        YamlUtils configs = new YamlUtils();
        Map<String, Object> yamlToMap = configs.getYamlToMap(BOOTSTRAP_YML_URL);
        //项目启动环境参数
        Object env = configs.getValue(ACTIVE_CONFIG, yamlToMap);
        //nacos 地址参数
        Object nacos = configs.getValue(NACOS_SERVER_ADDR, yamlToMap);
        /**
         * 判断nacos 是否有值,没有则使用
         */
        Object bootstrapNacos = configs.getValue(NACOS_SERVER_ADDR, yamlToMap);
        if (null == bootstrapNacos || "".equals(bootstrapNacos)){
            //参数默认读取dev
            nacos = AuthConstant.NACOS_DEV;
            env = AuthConstant.DEV;
        }
        //调用私有方法设置yaml 文件参数
        setNacosUrl(configs, NACOS_SERVER_ADDR, nacos !=null?nacos.toString():null, BOOTSTRAP_YML_URL, ACTIVE_CONFIG, env != null ? 		  env.toString() : null);
    }

私有方法(用于修改yml文件)

/**
     * 设置nacos 地址
     * @param configs
     * @param nacos           nacos项配置位置
     * @param nacosUrl        nacosUrl nacos路径
     * @param bootstrapYml    bootstrap 文件名称
     * @param activeConfig    项目启动的环境配置位置
     * @param env             环境变量
     */
    private void setNacosUrl(YamlUtils configs, String nacos, String nacosUrl, String bootstrapYml, String activeConfig, String env) {
        //修改nacos
        boolean flag = configs.updateYamlToNULL(nacos, nacosUrl, bootstrapYml);
        //修改启动配置
        configs.updateYamlToNULL(activeConfig, env, bootstrapYml);
        log.info("环境变量:" + env + "--------------->nacos地址:" + nacosUrl);
    }

对yml文件的修改

方法中用到了 String activeProfile = new ContextUtil().getActiveProfile(); 这个工具类。
当前工具类实现ApplicationContextAware方法注入bean
下面的工具类注意别落下

	
	public void nacosDate() throws IOException {
		//springBoot 启动时将环境参数放入了ApplicationContext 中,这个工具类就是获取ApplicationContext的环境参数
        String activeProfile = new ContextUtil().getActiveProfile();
        YamlUtils configs = new YamlUtils();
        Map<String, Object> yamlToMap = configs.getYamlToMap(BOOTSTRAP_YML_URL);
        System.out.println(yamlToMap);
        /**
         * 设置nacos 地址
         */
        if (AuthConstant.TEST.equals(activeProfile)) {
            setNacosUrl(configs, NACOS_SERVER_ADDR, AuthConstant.NACOS_TEST, BOOTSTRAP_YML_URL, ACTIVE_CONFIG, AuthConstant.TEST);
        } else if (AuthConstant.PROD.equals(activeProfile)) {
            setNacosUrl(configs, NACOS_SERVER_ADDR, AuthConstant.NACOS_PROD, BOOTSTRAP_YML_URL, ACTIVE_CONFIG, AuthConstant.PROD);
        } else {
            setNacosUrl(configs, NACOS_SERVER_ADDR, AuthConstant.NACOS_DEV, BOOTSTRAP_YML_URL, ACTIVE_CONFIG, AuthConstant.DEV);
        }
        Map<String, Object> yamlToMaprrrr = configs.getYamlToMap(BOOTSTRAP_YML_URL);
        System.out.println("更改后的nacos: " + yamlToMaprrrr.toString());
    }

ContextUtil工具类

使用@Component将类交由spring,非Boot 项目自己使用xml去注入
注意:在多模块项目中,这个工具类不要放到非启动的模块下比如common、core 之类的不需要启动的模块

@Component
public class ContextUtil implements ApplicationContextAware {

    private static ApplicationContext context;

    /* (non Javadoc)
     * @Title: setApplicationContext
     * @Description: spring获取bean工具类
     * @param applicationContext
     * @throws BeansException
     * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
     */
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("初始化了-----------------applicationContext");
        this.context = applicationContext;
    }

    // 传入线程中
    public static <T> T getBean(String beanName) {
        return (T) context.getBean(beanName);
    }

    // 国际化使用
    public static String getMessage(String key) {
        return context.getMessage(key, null, Locale.getDefault());
    }

    /// 获取当前环境
    public String getActiveProfile() {
        return context.getEnvironment().getActiveProfiles()[0];
    }

简单调用

这里有时间可以自己将启动类修集成一下,将动态修改yml 集成进去

@SpringBootApplication
public class ValueAddedApplication {

    public static void main(String[] args) throws IOException {
        new NacosConfig().upNacosData();
        SpringApplication.run(ValueAddedApplication.class,args);
        new NacosConfig().nacosDate();
    }
}

有没有其他好方法么,欢迎交流。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值