公司日前使用vertx构建rest服务,vertx工程跟普通的工程没有什么区别。我们使用gradle进行构建。后来随着部署发布的频繁,在打包之后再进行配置的修改,会出现很多的问题,很容易出错,然后排查问题花费很多时间,所以每次发布版本就跟打仗一样,提心吊胆的。后来经过研究,找到了两种多环境打包方式。第一种:将所有的配置文件打包到jar文件中,将所有的配置文件提出来单独放置到一个文件夹(利于查看配置)。我倾向于第一种,但是领导选择了第二种。
第一种,配置文件打包到jar文件
这种方式是利用gradle脚本的sourceSets设置,将配置文件包含进来,脚本如下:
plugins {
id 'application'
id 'com.github.johnrengelman.shadow' version '1.2.3'
id 'eclipse'
}
repositories {
jcenter()
}
def ver = System.getProperty("version")?:"1.0-SNAPSHOT";
//version = '1.0-SNAPSHOT'
version = ver
sourceCompatibility = '1.8'
mainClassName = 'io.vertx.core.Launcher'
applicationDefaultJvmArgs = ["-Dlogback.configurationFile=config/logback.xml"]
def vertxVersion = '3.3.3'
def mainVerticleName = 'io.vertx.starter.MainVerticle'
def watchForChange = 'src/**/*'
def doOnChange = './gradlew classes'
def env = System.getProperty("env")?:"prod"
dependencies {
compile "io.vertx:vertx-core:$vertxVersion"
compile "com.englishtown.vertx:vertx-jersey:4.5.2"
compile "com.englishtown.vertx:vertx-hk2:2.4.0"
compile 'com.jfinal:jfinal:2.2'
compile 'com.mchange:c3p0:0.9.5.2'
compile 'mysql:mysql-connector-java:5.1.40'
compile 'ch.qos.logback:logback-core:1.1.7'
compile 'ch.qos.logback:logback-classic:1.1.7'
compile 'org.json:json:20160810'
compile group: 'commons-codec', name: 'commons-codec', version: '1.9'
compile group: 'dom4j', name: 'dom4j', version: '1.6.1'
compile group: 'com.alibaba', name: 'fastjson', version: '1.1.43'
compile 'commons-configuration:commons-configuration:1.10'
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: '2.24.1'
compile ('com.sun.jersey:jersey-json:1.19.3'){
exclude group:'javax.ws.rs', module: 'jsr311-api'
}
testCompile "junit:junit:4.12"
testCompile "io.vertx:vertx-unit:$vertxVersion"
}
sourceSets {
main {
resources {
srcDirs = ["src/main/resources", "src/main/profile/$env"]
}
}
}
startScripts {
doLast {
unixScript.text = unixScript.text.replace('$CLASSPATH', '$APP_HOME/lib/*')
windowsScript.text = windowsScript.text.replace('%CLASSPATH%', '%APP_HOME%\\lib\\*')
}
}
shadowJar {
classifier = 'fat'
manifest {
attributes "Main-Verticle": mainVerticleName
}
mergeServiceFiles {
include 'META-INF/services/io.vertx.core.spi.VerticleFactory'
}
}
run {
args = ['run', mainVerticleName, "--redeploy=$watchForChange", "--launcher-class=$mainClassName", "--on-redeploy=$doOnChange"]
}
task wrapper(type: Wrapper) {
gradleVersion = '3.1'
}
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
打包之后的结构如下
所有的配置就在jar包中,所以代码里面需要从jar包中加载配置文件
1.loadJsonConfig【从jar中加载】
JsonConfigUtil.loadJarConfig(CONFIG_PATH + "config.json");
public static JsonObject loadJarConfig(String name){
if(null == name || "".equals(name)){
return null;
}
if(!name.startsWith("/")){// config/config.json
name = "/" + name;/// config/config.json
}
InputStream stream = JsonConfigUtil.class.getResourceAsStream(name);
Scanner scanner = new Scanner(stream, "UTF-8").useDelimiter("\\A");
return scanner.hasNext() ? new JsonObject(scanner.next()) : new JsonObject();
}
2.properties【PropertiesConfiguration从jar中加载】
PropertiesConfiguration serverConfig = new PropertiesConfiguration(CONFIG_PATH + "server.properties");
System.out.println("adminPrefix=============" + serverConfig.getString(SystemConfig.ADMIN_PREFIX));
3.properties【Properties从jar中加载】
Properties prop = io.vertx.starter.util.Utils.loadJarProp(CONFIG_PATH + "jdbc.properties");
System.out.println("password===========" + prop.getProperty("password"));
public static Properties loadJarProp(String name){
if(null == name || "".equals(name)){
return null;
}
if(!name.startsWith("/")){// config/config.json
name = "/" + name;/// config/config.json
}
InputStream stream = Utils.class.getResourceAsStream(name);
Properties properties = new Properties();
try{
properties.load(stream);
}
catch(IOException e){
e.printStackTrace();
}
return properties;
}
第二种,配置文件单独分离出来
这种方式利用拷贝任务将配置拷贝至dist目录下,打包的时候就把这些文件打包到发布目录下,脚本如下:
plugins {
id 'application'
id 'com.github.johnrengelman.shadow' version '1.2.3'
id 'eclipse'
}
repositories {
jcenter()
}
version = System.getProperty("version")?:"1.0-SNAPSHOT"
def env = System.getProperty("env")?:"prod"
sourceCompatibility = '1.8'
mainClassName = 'io.vertx.core.Launcher'
applicationDefaultJvmArgs = ["-Dlogback.configurationFile=config/logback.xml"]
def vertxVersion = '3.3.3'
def mainVerticleName = 'io.vertx.starter.MainVerticle'
def watchForChange = 'src/**/*'
def doOnChange = './gradlew classes'
dependencies {
compile "io.vertx:vertx-core:$vertxVersion"
compile "com.englishtown.vertx:vertx-jersey:4.5.2"
compile "com.englishtown.vertx:vertx-hk2:2.4.0"
compile 'com.jfinal:jfinal:2.2'
compile 'com.mchange:c3p0:0.9.5.2'
compile 'mysql:mysql-connector-java:5.1.40'
compile 'ch.qos.logback:logback-core:1.1.7'
compile 'ch.qos.logback:logback-classic:1.1.7'
compile 'org.json:json:20160810'
compile group: 'commons-codec', name: 'commons-codec', version: '1.9'
compile group: 'dom4j', name: 'dom4j', version: '1.6.1'
compile group: 'com.alibaba', name: 'fastjson', version: '1.1.43'
compile 'commons-configuration:commons-configuration:1.10'
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: '2.24.1'
compile ('com.sun.jersey:jersey-json:1.19.3'){
exclude group:'javax.ws.rs', module: 'jsr311-api'
}
testCompile "junit:junit:4.12"
testCompile "io.vertx:vertx-unit:$vertxVersion"
}
startScripts {
doLast {
unixScript.text = unixScript.text.replace('$CLASSPATH', '$APP_HOME/lib/*')
windowsScript.text = windowsScript.text.replace('%CLASSPATH%', '%APP_HOME%\\lib\\*')
}
}
shadowJar {
classifier = 'fat'
manifest {
attributes "Main-Verticle": mainVerticleName
}
mergeServiceFiles {
include 'META-INF/services/io.vertx.core.spi.VerticleFactory'
}
}
run {
args = ['run', mainVerticleName, "--redeploy=$watchForChange", "--launcher-class=$mainClassName", "--on-redeploy=$doOnChange"]
}
task wrapper(type: Wrapper) {
gradleVersion = '3.1'
}
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
task copyRightConfig(type: Copy) {
File file1 = new File("src/main/dist/");
file1.deleteDir();
copy{
println('copyRightConfig task begins')
from("src/main/profile/$env") {
//include('**/*.*')
}
into('src/main/dist/')
println('copyRightConfig task ends')
}
}
/*
task('copyRightConfig', type: Copy) {
println('copyRightConfig task begins')
from(file('src/main/profile/profile/prod/config'))
into('src/main/dist')
println('copyRightConfig task ends')
}*/
//assembleDist.mustRunAfter copyRightConfig
assembleDist.dependsOn copyRightConfig
打包之后的结构
配置被单独拎出来了
1.loadJsonConfig【从jar中加载】
String path = new PropertiesConfiguration(CONFIG_PATH + "config.json").getPath();
System.out.println(path);
JsonObject config = JsonConfigUtil.loadConfig(path);
public static JsonObject loadConfig(String name) {
try (InputStream is = new FileInputStream(name)) {
try (Scanner scanner = new Scanner(is, "UTF-8").useDelimiter("\\A")) {
return scanner.hasNext() ? new JsonObject(scanner.next()) : new JsonObject();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
2.properties【PropertiesConfiguration从拎出来的中加载】
PropertiesConfiguration serverConfig = new PropertiesConfiguration(CONFIG_PATH + "server.properties");
SystemConfig.initSystemConfig(serverConfig);
3.properties【Properties从拎出来的地方加载】
PropertiesConfiguration jdbcConfig = null;
jdbcConfig = new PropertiesConfiguration(CONFIG_PATH + "jdbc.properties");
C3p0Plugin c3p0Plugin = new C3p0Plugin(jdbcConfig.getString("jdbcUrl"), jdbcConfig.getString("user"),
jdbcConfig.getString("password"));
plugins {
id 'application'
id 'com.github.johnrengelman.shadow' version '1.2.3'
id 'eclipse'
}
repositories {
jcenter()
}
version = System.getProperty("version")?:"1.0-SNAPSHOT"
def env = System.getProperty("env")?:"prod"
sourceCompatibility = '1.8'
mainClassName = 'io.vertx.core.Launcher'
applicationDefaultJvmArgs = ["-Dlogback.configurationFile=config/logback.xml"]
def vertxVersion = '3.3.3'
def mainVerticleName = 'io.vertx.starter.MainVerticle'
def watchForChange = 'src/**/*'
def doOnChange = './gradlew classes'
dependencies {
compile "io.vertx:vertx-core:$vertxVersion"
compile "com.englishtown.vertx:vertx-jersey:4.5.2"
compile "com.englishtown.vertx:vertx-hk2:2.4.0"
compile 'com.jfinal:jfinal:2.2'
compile 'com.mchange:c3p0:0.9.5.2'
compile 'mysql:mysql-connector-java:5.1.40'
compile 'ch.qos.logback:logback-core:1.1.7'
compile 'ch.qos.logback:logback-classic:1.1.7'
compile 'org.json:json:20160810'
compile group: 'commons-codec', name: 'commons-codec', version: '1.9'
compile group: 'dom4j', name: 'dom4j', version: '1.6.1'
compile group: 'com.alibaba', name: 'fastjson', version: '1.1.43'
compile 'commons-configuration:commons-configuration:1.10'
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: '2.24.1'
compile ('com.sun.jersey:jersey-json:1.19.3'){
exclude group:'javax.ws.rs', module: 'jsr311-api'
}
testCompile "junit:junit:4.12"
testCompile "io.vertx:vertx-unit:$vertxVersion"
}
startScripts {
doFirst {
println 'build start'
File file1 = new File("src/main/dist/");
file1.deleteDir();
copy{
println('copyRightConfig task begins')
from("src/main/profile/$env") {
//include('**/*.*')
}
into('src/main/dist/')
println('copyRightConfig task ends')
}
}
doLast {
unixScript.text = unixScript.text.replace('$CLASSPATH', '$APP_HOME/lib/*')
windowsScript.text = windowsScript.text.replace('%CLASSPATH%', '%APP_HOME%\\lib\\*')
}
}
shadowJar {
classifier = 'fat'
manifest {
attributes "Main-Verticle": mainVerticleName
}
mergeServiceFiles {
include 'META-INF/services/io.vertx.core.spi.VerticleFactory'
}
}
run {
args = ['run', mainVerticleName, "--redeploy=$watchForChange", "--launcher-class=$mainClassName", "--on-redeploy=$doOnChange"]
}
task wrapper(type: Wrapper) {
gradleVersion = '3.1'
}
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
两者的运行命令都是
gradle clean
gradle build -Denv=prod -Dversion=1.2.3
gradle build -Denv=test -Dversion=1.2.4