在Java系统开发中,各种配置文件管理是非常常见且重要的工作,配置文件包括传统的键值对配置文件(properties文件),XML文件(Spring的Bean定义),YAML文件(Spring Boot中常用)等,如果系统中需要使用多个配置文件,且配置文件的类型不一样时,配置文件的管理将是一个很头疼的问题,现在有一个全新的配置文件管理工具,欢迎各位开发人员多多尝试。

依赖引用

最新版本为1.2.2,使用时请替换${version}为对应的版本号 Maven:

<dependency>
    <groupId>org.nervousync</groupId>
	<artifactId>utils-jdk11</artifactId>
    <version>${version}</version>
</dependency>

Gradle:

Manual: compileOnly group: 'org.nervousync', name: 'utils-jdk11', version: '${version}'
Short: compileOnly 'org.nervousync:utils-jdk11:${version}'

SBT:

libraryDependencies += "org.nervousync" % "utils-jdk11" % "${version}" % "provided"

Ivy:

<dependency org="org.nervousync" name="utils-jdk11" rev="${version}"/>

配置文件的特殊之处

配置文件在Java系统中起着关键作用,它们主要用于解耦代码与环境、提高灵活性和可维护性,当系统需要同时使用多个配置文件时,拥有一个能够统一管理的配置文件管理器,将给开发工作提供很大帮助。配置文件中经常会保存一些敏感信息(包括Api Key、密钥数据、密码等),如果能够将这些敏感信息在保存时自动加密,读取时自动解密,那么可以很好的保护敏感信息,在意外泄漏配置文件时,也不会导致敏感信息泄漏。

配置文件定义

开发人员在需要定义新的配置文件时,仅需要定义一个JavaBean,并继承 org.nervousync.beans.core.BeanObject 抽象类,在JavaBean中定义好配置文件信息,在JavaBean的类定义上添加 org.nervousync.annotations.beans.OutputConfig 注解,至此配置文件已经完成。

如果使用的是XML格式的配置文件,需要在JavaBean中添加对应的JAXB的注解信息

OutputConfig注解的参数:

参数名 数据类型 备注
type StringUtils.StringType 默认为SERIALIZABLE(序列化),可选JSON、YAML、XML
formatted 布尔值 true:格式化输出(方便阅读),false:所有数据在一行显示
encoding 字符串 使用的编码集,默认为“UTF-8”

不同 StringUtils.StringType 值对应的文件扩展名:

数据类型 文件扩展名
SERIALIZABLE dat
JSON json
YAML yml 或 yaml
XML xml

配置文件定义示例:

/*
 * Licensed to the Nervousync Studio (NSYC) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.nervousync.proxy;

import java.net.Proxy.Type;

import jakarta.xml.bind.annotation.*;
import org.nervousync.annotations.configs.Password;
import org.nervousync.beans.core.BeanObject;
import org.nervousync.commons.Globals;

/**
 * <h2 class="en-US">Proxy server configure</h2>
 * <h2 class="zh-CN">代理服务器配置信息</h2>
 *
 * @author Steven Wee	<a rel="nofollow" href="mailto:wmkm0113@gmail.com">wmkm0113@gmail.com</a>
 * @version $Revision: 1.0.0 $ $Date: Jan 4, 2018 16:05:54 $
 */
@XmlType(name = "proxy_config", namespace = "https://nervousync.org/schemas/proxy")
@XmlRootElement(name = "proxy_config", namespace = "https://nervousync.org/schemas/proxy")
@XmlAccessorType(XmlAccessType.NONE)
public final class ProxyConfig extends BeanObject {
	/**
	 * <span class="en-US">Serial version UID</span>
	 * <span class="zh-CN">序列化UID</span>
	 */
	private static final long serialVersionUID = -5386443812775715018L;
	/**
	 * <span class="en-US">Enumeration value of proxy type</span>
	 * <span class="zh-CN">代理服务器类型枚举值</span>
	 */
	@XmlElement(name = "type")
	private Type proxyType = Type.DIRECT;
	/**
	 * <span class="en-US">Proxy server address</span>
	 * <span class="zh-CN">代理服务器地址</span>
	 */
	@XmlElement(name = "address")
	private String proxyAddress = Globals.DEFAULT_VALUE_STRING;
	/**
	 * <span class="en-US">Proxy server port</span>
	 * <span class="zh-CN">代理服务器端口号</span>
	 */
	@XmlElement(name = "port")
	private int proxyPort = Globals.DEFAULT_VALUE_INT;
	/**
	 * <span class="en-US">Authenticate username</span>
	 * <span class="zh-CN">身份认证用户名</span>
	 */
	@XmlElement(name = "username")
	private String userName = Globals.DEFAULT_VALUE_STRING;
	/**
	 * <span class="en-US">Authenticate password</span>
	 * <span class="zh-CN">身份认证密码</span>
	 */
	@XmlElement(name = "password")
	private String password = Globals.DEFAULT_VALUE_STRING;
	/**
	 * <span class="en-US">Last modified timestamp</span>
	 * <span class="zh-CN">最后修改时间戳</span>
	 */
	@XmlElement(name = "last_modified")
	private long lastModified = Globals.DEFAULT_VALUE_LONG;

	/**
	 * <h3 class="en-US">Constructor method for ProxyConfig</h3>
	 * <h3 class="zh-CN">ProxyConfig构造方法</h3>
	 */
	public ProxyConfig() {
	}

	/**
	 * <h3 class="en-US">Static method for create redirect ProxyConfig instance</h3>
	 * <h3 class="zh-CN">静态方法用于创建无代理的代理服务器配置信息实例对象</h3>
	 *
	 * @return <span class="en-US">Generated ProxyConfig instance</span>
	 * <span class="zh-CN">生成的代理服务器配置信息实例对象</span>
	 */
	public static ProxyConfig redirect() {
		return new ProxyConfig();
	}

	/**
	 * <h3 class="en-US">Getter method for proxy type</h3>
	 * <h3 class="zh-CN">代理服务器类型的Getter方法</h3>
	 *
	 * @return <span class="en-US">Enumeration value of proxy type</span>
	 * <span class="zh-CN">代理服务器类型枚举值</span>
	 */
	public Type getProxyType() {
		return proxyType;
	}

	/**
	 * <h3 class="en-US">Setter method for proxy type</h3>
	 * <h3 class="zh-CN">代理服务器类型的Setter方法</h3>
	 *
	 * @param proxyType <span class="en-US">Enumeration value of proxy type</span>
	 *                  <span class="zh-CN">代理服务器类型枚举值</span>
	 */
	public void setProxyType(Type proxyType) {
		this.proxyType = proxyType;
	}

	/**
	 * <h3 class="en-US">Getter method for proxy type</h3>
	 * <h3 class="zh-CN">代理服务器类型的Getter方法</h3>
	 *
	 * @return <span class="en-US">Proxy server address</span>
	 * <span class="zh-CN">代理服务器地址</span>
	 */
	public String getProxyAddress() {
		return proxyAddress;
	}

	/**
	 * <h3 class="en-US">Setter method for proxy type</h3>
	 * <h3 class="zh-CN">代理服务器类型的Setter方法</h3>
	 *
	 * @param proxyAddress <span class="en-US">Proxy server address</span>
	 *                     <span class="zh-CN">代理服务器地址</span>
	 */
	public void setProxyAddress(String proxyAddress) {
		this.proxyAddress = proxyAddress;
	}

	/**
	 * <h3 class="en-US">Getter method for proxy type</h3>
	 * <h3 class="zh-CN">代理服务器类型的Getter方法</h3>
	 *
	 * @return <span class="en-US">Proxy server port</span>
	 * <span class="zh-CN">代理服务器端口号</span>
	 */
	public int getProxyPort() {
		return proxyPort;
	}

	/**
	 * <h3 class="en-US">Setter method for proxy type</h3>
	 * <h3 class="zh-CN">代理服务器类型的Setter方法</h3>
	 *
	 * @param proxyPort <span class="en-US">Proxy server port</span>
	 *                  <span class="zh-CN">代理服务器端口号</span>
	 */
	public void setProxyPort(int proxyPort) {
		this.proxyPort = proxyPort;
	}

	/**
	 * <h3 class="en-US">Getter method for proxy type</h3>
	 * <h3 class="zh-CN">代理服务器类型的Getter方法</h3>
	 *
	 * @return <span class="en-US">Authenticate username</span>
	 * <span class="zh-CN">身份认证用户名</span>
	 */
	public String getUserName() {
		return userName;
	}

	/**
	 * <h3 class="en-US">Setter method for proxy type</h3>
	 * <h3 class="zh-CN">代理服务器类型的Setter方法</h3>
	 *
	 * @param userName <span class="en-US">Authenticate username</span>
	 *                 <span class="zh-CN">身份认证用户名</span>
	 */
	public void setUserName(String userName) {
		this.userName = userName;
	}

	/**
	 * <h3 class="en-US">Getter method for proxy type</h3>
	 * <h3 class="zh-CN">代理服务器类型的Getter方法</h3>
	 *
	 * @return <span class="en-US">Authenticate password</span>
	 * <span class="zh-CN">身份认证密码</span>
	 */
	public String getPassword() {
		return password;
	}

	/**
	 * <h3 class="en-US">Setter method for proxy type</h3>
	 * <h3 class="zh-CN">代理服务器类型的Setter方法</h3>
	 *
	 * @param password <span class="en-US">Authenticate password</span>
	 *                 <span class="zh-CN">身份认证密码</span>
	 */
	public void setPassword(String password) {
		this.password = password;
	}

	/**
	 * <h3 class="en-US">Getter method for the last modified timestamp</h3>
	 * <h3 class="zh-CN">最后修改时间戳的Getter方法</h3>
	 *
	 * @return <span class="en-US">Last modified timestamp</span>
	 * <span class="zh-CN">最后修改时间戳</span>
	 */
	public long getLastModified() {
		return this.lastModified;
	}

	/**
	 * <h3 class="en-US">Setter method for the last modified timestamp</h3>
	 * <h3 class="zh-CN">最后修改时间戳的Setter方法</h3>
	 *
	 * @param lastModified <span class="en-US">Last modified timestamp</span>
	 *                     <span class="zh-CN">最后修改时间戳</span>
	 */
	public void setLastModified(final long lastModified) {
		this.lastModified = lastModified;
	}
}

配置文件管理器

在调用 org.nervousync.configs.ConfigureManager 的 getInstance() 静态方法时,系统会自动初始化配置文件管理器,配置文件的默认保存位置为当前用户工作目录下名为“.configs”的文件夹中,如果需要自定义配置文件的保存位置,需要调用 org.nervousync.configs.ConfigureManager 的 initialize 静态方法,将自定义保存位置路径字符串作为参数传入。

注意: 配置文件管理器使用单例模式运行。

1.检查配置文件是否存在

调用 org.nervousync.configs.ConfigureManager 实例对象的 checkExists 方法检查配置文件是否存在,方法返回值类型为布尔值,文件存在返回“true”,文件不存在返回“false”。

checkExists方法的参数:

参数名 数据类型 备注
targetClass Class<? extends BeanObject> 配置信息定义类
suffix 字符串 配置文件自定义后缀,用于区分同一类型的不同配置信息(可选参数)

2.写入配置文件

调用 org.nervousync.configs.ConfigureManager 实例对象的 saveConfigure 方法保存配置文件对象,方法返回值类型为布尔值,保存成功返回“true”,保存失败返回“false”。

saveConfigure方法的参数:

参数名 数据类型 备注
beanObject org.nervousync.beans.core.BeanObject 配置信息实例对象
suffix 字符串 配置文件自定义后缀,用于区分同一类型的不同配置信息(可选参数)

3.读取配置文件

调用 org.nervousync.configs.ConfigureManager 实例对象的 readConfigure 方法读取配置文件,方法返回值为给定配置信息定义类的实例对象,文件存在返回实例对象,文件不存在返回 null 。

readConfigure方法的参数:

参数名 数据类型 备注
targetClass Class<? extends BeanObject> 配置信息定义类
suffix 字符串 配置文件自定义后缀,用于区分同一类型的不同配置信息(可选参数)

4.删除配置文件

调用 org.nervousync.configs.ConfigureManager 实例对象的 removeConfigure 方法读取配置文件,方法返回值类型为布尔值,删除成功返回“true”,删除失败返回“false”。

removeConfigure方法的参数:

参数名 数据类型 备注
targetClass Class<? extends BeanObject> 配置信息定义类
suffix 字符串 配置文件自定义后缀,用于区分同一类型的不同配置信息(可选参数)

注意: 如果suffix参数为空,则删除所有类型为给定配置信息定义类的配置文件。

5.转换配置文件类型

调用 org.nervousync.configs.ConfigureManager 实例对象的 convertType 方法读取配置文件,方法返回值类型为布尔值,转换成功返回“true”,转换失败返回“false”。

removeConfigure方法的参数:

参数名 数据类型 备注
targetClass Class<? extends BeanObject> 配置信息定义类
originalType StringUtils.StringType 原始数据类型
targetType StringUtils.StringType 转换后的数据类型
suffix 字符串 配置文件自定义后缀,用于区分同一类型的不同配置信息(可选参数)

注意: 如果suffix参数为空,则转换所有类型为给定配置信息定义类的配置文件。

敏感信息的保护

当某些字段保存的数据为敏感信息时,仅需要在字段上使用 org.nervousync.annotations.configs.Password 标注即可,默认使用AES256加密算法来保护敏感信息,配置信息管理器会在保存文件时自动加密该字段,在读取文件时自动解密该字段。

示例代码:

/**
 * <span class="en-US">Authenticate password</span>
 * <span class="zh-CN">身份认证密码</span>
 */
@Password
@XmlElement(name = "password")
private String password = Globals.DEFAULT_VALUE_STRING;

使用自定义的加密算法

1.配置加密算法

调用 org.nervousync.security.factory.SecureFactory 的 initConfig 静态方法初始化加密算法配置。

initConfig方法的参数:

参数名 数据类型 备注
secureName 字符串 安全配置名称
secureAlgorithm SecureFactory.SecureAlgorithm 使用的加密算法,支持:RSA1024, RSA2048, SM2, AES128, AES192, AES256, DES, TRIPLE_DES, SM4

2.使用安全配置

修改 org.nervousync.annotations.configs.Password 标注的 value 参数为刚刚初始化的安全配置名称,即可使用自定义的加密算法来保护敏感信息。

配置文件的自动加载

开发人员可以通过简单的修改来实现配置文件的自动加载,省去读取配置文件的代码操作。

1.定义配置文件属性

添加类型为配置文件的属性,并使用 org.nervousync.annotations.configs.Configuration 标注,可以通过标注的 value 参数修改需要使用的配置文件后缀名,将包含属性类型为配置文件的类继承 org.nervousync.configs.AutoConfig 抽象类。

2.初始化并测试自动加载

通过 new 创建类的实例对象,可以发现创建的实例对象中,类型为配置文件的属性值已经自动加载完成(如果配置文件存在)。

版权信息

转载请注明出处:https://blog.51cto.com/commandos