Java生成软件配置
我正在从事一个项目,其中包含一些用于datasource、MQ和其他内容的.properties配置文件。我们也有启动shell脚本和用户配置文件脚本。我面临的问题是,我们确实在5个不同的环境中部署了这个软件,当然,每个环境的配置都不同。使用该配置维护大约30个纯文本文件有点困难。它们中的大多数几乎是相同的,就像shell脚本一样,它们只有一些不同的路径引用 你们知道我可以在构建脚本中集成什么工具,可以从单个文件或嵌入式数据库中获取这些属性,然后生成适当的环境配置吗?如果它也能生成脚本,那就更有趣了Java生成软件配置,java,configuration,Java,Configuration,我正在从事一个项目,其中包含一些用于datasource、MQ和其他内容的.properties配置文件。我们也有启动shell脚本和用户配置文件脚本。我面临的问题是,我们确实在5个不同的环境中部署了这个软件,当然,每个环境的配置都不同。使用该配置维护大约30个纯文本文件有点困难。它们中的大多数几乎是相同的,就像shell脚本一样,它们只有一些不同的路径引用 你们知道我可以在构建脚本中集成什么工具,可以从单个文件或嵌入式数据库中获取这些属性,然后生成适当的环境配置吗?如果它也能生成脚本,那就更有
谢谢
< P> Maven提供了如下的框:.< /P> < P>我是C++和java语言中的配置文件解析器库的维护者。Config4*配置文件中的大多数内容都是name=value语句,但您可以引用环境变量和执行某些命令(如hostname
)的标准输出。配置文件中还可以包含if-then-else语句。例如(关键字前缀为“@”):
我称之为适应性配置,因为单个配置文件可以将其内容适应各种主机、用户名等。Config4*提供了一种将命令行选项与配置文件集成的简单方法,因此可以有一个配置文件,该文件可以根据命令行选项(如-env production
或-env staging
)的存在来调整其内容。例如:
env ?= ""; # set by a command-line option
if (env == "production") {
... # set variables to values for production environment
} @elseIf (env == "staging") {
... # set variables to values for staging environment
} @else {
@error "You must specify '-env production' or '-env staging' as a command-line option";
}
我可以想出两种可能的方法,Config4*可能会对您有所帮助
一个选项是在应用程序中嵌入Config4*解析器。然而,尽管我认为这是开发新应用程序时的一个好方法,但我认为将Config4*改造为现有应用程序可能会很乏味(不是因为Config4*很难使用,而是因为您将修改使用Java属性API或XML API的现有代码以使用不同的API,而这样的修改往往很乏味)
第二个选项更适合您问题的具体情况。您可以编写shell脚本和属性文件的模板版本。这些模板文件将使用特定语法,例如
'${variable.name}“
指定配置文件中的值应在何处使用。然后,您可以编写一个小型实用程序应用程序,该应用程序读取模板文件和配置文件,执行所需的替换,然后将转换后的文件写入磁盘。您可以从生成系统运行该实用程序应用程序。您可以查看ewly宣布,它允许您在运行时而不是构建时处理配置。在前面的回答中,我概述了如何满足您的需求。我决定吃自己的狗粮,所以我设计了一个基于Config4*的应用程序,可以随时编译和运行。我在这个回答中提供内联代码,而不是r通过StackOverview网页阅读代码,您可能会发现更容易将代码复制并粘贴到文件中,这样您就可以使用文本编辑器查看代码
首先,我们需要一个定义三个变量的配置文件:
(指定为命令行参数,其值为deploymentType
、dev
或staging
)prod
(成对的模板文件和输出文件)文件
(要应用于模板文件以生成输出文件的搜索和替换字符串对)。使用的字符串对取决于searchAndReplace
的值deploymentType
templates.cfg
):
这是应用程序的主线。您应该将以下内容剪切粘贴到实例化模板文件中。java
:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import org.config4j.Configuration;
import org.config4j.SchemaValidator;
import org.config4j.ConfigurationException;
public class InstantiateTemplateFiles
{
public static void main(String[] args)
{
Configuration cfg = Configuration.create();
SchemaValidator sv = new SchemaValidator();
String[] searchAndReplace;
String[] files;
String contents;
String modifiedContents;
String templateFile;
String outputFile;
int i;
String[] schema = new String[] {
"deploymentType = string",
"searchAndReplace=table[string,search, string,replace]",
"files=table[string,template-file, string,output-file]",
};
if (args.length != 2) {
System.err.println("\nusage: java InstantiateTemplateFiles"
+ " meta-config-file.cfg deploymentType\n");
System.exit(1);
}
try {
//--------
// Parse the configuration file, perform schema validation
// and retrieve the required configuration variables.
//--------
cfg.insertString("", "deploymentType", args[1]);
cfg.parse(args[0]);
sv.parseSchema(schema);
sv.validate(cfg, "", "");
searchAndReplace = cfg.lookupList("", "searchAndReplace");
files = cfg.lookupList("", "files");
//--------
// Do the real work
//--------
for (i = 0; i < files.length; i += 2) {
Util.searchAndReplaceInFile(files[i + 0], files[i + 1],
searchAndReplace);
}
} catch(IOException ex) {
System.err.println("\n" + ex.getMessage() + "\n");
System.exit(1);
} catch(ConfigurationException ex) {
System.err.println("\n" + ex.getMessage() + "\n");
System.exit(1);
}
}
}
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class Util
{
public static void searchAndReplaceInFile(
String inputFile,
String outputFile,
String[] searchAndReplacePairs) throws IOException
{
String contents;
String modifiedContents;
contents = Util.readTextFile(inputFile);
modifiedContents = Util.replace(contents, searchAndReplacePairs);
Util.writeTextFile(outputFile, modifiedContents);
}
public static String readTextFile(String fileName) throws IOException
{
BufferedReader in;
StringBuffer result;
String line;
result = new StringBuffer();
in = new BufferedReader(new FileReader(fileName));
while ((line = in.readLine()) != null) {
result.append(line).append("\n");
}
in.close();
return result.toString();
}
public static void writeTextFile(String fileName, String contents)
throws IOException
{
PrintWriter out;
StringBuffer result;
String line;
out = new PrintWriter(new BufferedWriter(new FileWriter(fileName)));
out.print(contents);
out.close();
}
public static String replace(
String origStr,
String searchStr,
String replacementStr)
{
StringBuffer result;
int origStrLen;
int searchStrLen;
int currStart;
int pIndex;
result = new StringBuffer();
origStrLen = origStr.length();
searchStrLen = searchStr.length();
currStart = 0;
pIndex = origStr.indexOf(searchStr, currStart);
while (pIndex != -1) {
result.append(origStr.substring(currStart, pIndex));
result.append(replacementStr);
currStart = pIndex + searchStrLen;
pIndex = origStr.indexOf(searchStr, currStart);
}
result.append(origStr.substring(currStart));
return result.toString();
}
public static String replace(
String origStr,
String[] searchAndReplacePairs)
{
int i;
int currIndex;
String subStr;
String replaceStr;
StringBuffer result;
SearchAndReplacePair[] pairs;
SearchAndReplacePair nextPair;
pairs = new SearchAndReplacePair[searchAndReplacePairs.length / 2];
for (i = 0; i < searchAndReplacePairs.length; i += 2) {
pairs[i/2] = new SearchAndReplacePair(origStr,
searchAndReplacePairs[i + 0],
searchAndReplacePairs[i + 1]);
}
result = new StringBuffer();
currIndex = 0;
nextPair = findNextPair(origStr, currIndex, pairs);
while (nextPair != null) {
subStr = origStr.substring(currIndex, nextPair.indexOf);
result.append(subStr);
result.append(nextPair.replace);
currIndex = nextPair.indexOf + nextPair.length;
for (i = 0; i < pairs.length; i++) {
pairs[i].findNext(currIndex);
}
nextPair = findNextPair(origStr, currIndex, pairs);
}
subStr = origStr.substring(currIndex);
result.append(subStr);
return result.toString();
}
private static SearchAndReplacePair findNextPair(
String origStr,
int currIndex,
SearchAndReplacePair[] pairs)
{
int i;
SearchAndReplacePair bestSoFar;
SearchAndReplacePair item;
bestSoFar = null;
for (i = 0; i < pairs.length; i++) {
item = pairs[i];
if (item.indexOf == -1) {
continue;
}
if (bestSoFar == null) {
bestSoFar = item;
continue;
}
if (bestSoFar.indexOf < item.indexOf) {
continue;
}
if (bestSoFar.indexOf > item.indexOf) {
bestSoFar = item;
continue;
}
if (bestSoFar.length < item.length) {
bestSoFar = item;
}
}
return bestSoFar;
}
}
class SearchAndReplacePair
{
String source;
String search;
String replace;
int length;
int indexOf;
int sourceLength;
public SearchAndReplacePair(String source, String search, String replace)
{
this.source = source;
this.sourceLength = source.length();
this.search = search;
this.replace = replace;
this.length = search.length();
this.indexOf = source.indexOf(search);
}
public void findNext(int fromIndex)
{
if (indexOf == -1 || indexOf + 1 == sourceLength) {
indexOf = -1;
} else {
indexOf = source.indexOf(search, fromIndex);
}
}
}
假设您已下载并安装了Config4J(从网站),则可以使用以下内容编译该实用程序:
CLASSPATH=.:/path/to/config4j.jar;
export CLASSPATH
javac -classpath .:/ag/projects/config4j/lib/config4j.jar *.java
下面是一个运行它的示例:
java InstantiateTemplateFiles templates.cfg prod
如果文件hello template.sh
如下所示:
#!/bin/sh
DB_HOST=${db.host}
DB_USER=${db.user}
DB_LOG_LEVEL=${db.log.level}
echo Hello from $DB_USER at log level $DB_LOG_LEVEL on host $DB_HOST
然后生成的hello.sh
文件如下所示:
#!/bin/sh
DB_HOST=production.example.com
DB_USER=cjmchale
DB_LOG_LEVEL=0
echo Hello from $DB_USER at log level $DB_LOG_LEVEL on host $DB_HOST
#!/bin/sh
DB_HOST=${db.host}
DB_USER=${db.user}
DB_LOG_LEVEL=${db.log.level}
echo Hello from $DB_USER at log level $DB_LOG_LEVEL on host $DB_HOST
#!/bin/sh
DB_HOST=production.example.com
DB_USER=cjmchale
DB_LOG_LEVEL=0
echo Hello from $DB_USER at log level $DB_LOG_LEVEL on host $DB_HOST