将 Groovy 融入项目的部署过程
配置文件的编写一直都是个烦心事。properties 文件表现力不强,不能很好的描述,list 之类的配置。json 文件作为配置文件凑活,但是标准的 json 是没有注释的,也是一个缺陷。xml 的表现力足够好,但是配置一但增大,xml 文件就会看起来很乱,可读性下降。所以我想用脚本语言 groovy 来作为项目中的配置文件,既有很强的表达力,又有很好的可读性。
普通配置类
项目内部的配置,我是建议有一个独立的或者嵌套的配置类,所有属性私有,不需要 set 方法,能有默认值就把默认值写出来,配置文件类的属性全部都是只读的。例如:
public class MainConfig {
private boolean debug = true;
private int port = 1234;
private String payurl = "www.gofreeteam.com";
private String logPath = "/var/lib/tomcat7/logs/catalina.out";
private DbConfig db;
public String getLogPath() {
return logPath;
}
public String getPayurl() {
return payurl;
}
public int getPort() {
return port;
}
public boolean isDebug() {
return debug;
}
public DbConfig getDb() {
return db;
}
}</pre>
为了修改配置文件的内容,我们只需要编写一个返回对应类型的 groovy 文件就好:
def config = new com.gofreeteam.master.config.MainConfig();
config.debug = true;
config.port = 4321
if (config.debug){
config.db = ConfigFactory.newScriptConfig("DbConfig.test.groovy");
config.payurl = "http://www.gofreeteam.com:8080/SSM/alipay/payToUsers.do?token=\$&orders=";
config.logPath = "C:/test.log";
}else{
config.db = ConfigFactory.newScriptConfig("DbConfig.public.groovy");
config.payurl = "http://www.gofreeteam.com/alipay/payToUsers.do?token=\$&orders=";
}
return config</pre>
groovy 文件是当作资源存放在 Maven 工程的 Resouce 目录下的。并不是作为源码放在 java 目录下。这样可以让 groovy 文件保持为脚本状态,方便修改内容。到读取配置文件内容也就需要一个中间类来解析 groovy 了。所以我封装了一个通用的工厂类。
package club.fullstack.common4j.util;
import groovy.lang.GroovyObject;
import groovy.util.GroovyScriptEngine;
import java.net.URL;
import java.util.Map;
import java.util.WeakHashMap;
/**
* Created by Cheney on 2016/10/29.
* 使用脚本化的 config 文件
*/
public class ConfigFactory {
private static Map<Class,Object> defaultInstances = new WeakHashMap<Class, Object>();
private static Map<String,Object> scriptInstances = new WeakHashMap<String, Object>();
public static <T> T getDefaultConfig(Class configClass) {
Object instance = defaultInstances.get(configClass);
if ( null == instance ){
instance = newDefaultConfig(configClass);
defaultInstances.put(configClass,instance);
}
return (T)instance;
}
public static <T> T getScriptConfig(String path){
Object instance = scriptInstances.get(path);
if ( null == instance ){
instance = newScriptConfig(path);
scriptInstances.put(path,instance);
}
return (T)instance;
}
public static <T> T getScriptConfig(Class configClass){
String className = configClass.getName();
className = className.substring(className.lastIndexOf(".") +1,className.length());
return getScriptConfig(className + ".groovy");
}
public static <T> T newDefaultConfig(Class configClass) {
try {
return (T)configClass.newInstance();
} catch (Exception e) {
System.out.println(e);
System.out.println("配置类型实例化失败");
}
return null;
}
public static <T> T newScriptConfig(Class config){
String className = config.getName();
className = className.substring(className.lastIndexOf(".") +1,className.length());
return newScriptConfig(className + ".groovy");
}
public static <T> T newScriptConfig(String path) {
try{
URL[] root = new URL[]{
ConfigFactory.class.getResource(""),
ConfigFactory.class.getResource("/")
};
GroovyScriptEngine gse = new GroovyScriptEngine(root);
GroovyObject groovyObject = (GroovyObject) gse.loadScriptByName(path).newInstance();
return (T) groovyObject.invokeMethod("run",null);
}catch (Exception e){
System.out.println(e);
System.out.println("加载配置文件失败");
}
return null;
}
}
</pre>
以后写配置文件就简单多了,其实就是用脚本 new 了 Config 对象,改修改的值改改,甚至可以加入一定的逻辑,根据操作系统不同,变成不同的配置等。
项目部署配置
大型的网站项目,我本会打 WAR 包放到 Tomcat 下运行。但是对于小型项目,比如 api 接口等小而多的项目通常内嵌 jetty 自主运行,这种项目部署也可以用 Groovy 脚本来解决。
我写了一个简单的用 groovy 调用 jetty 来启动某个项目的脚本。
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.webapp.WebAppContext
/**
* Created by Cheney on 2016/11/3.
*/
def port = 4321
def project_name = "master"
def mainconfig_name = "MainConfig.groovy"
Server server = new Server(4321);
server.setStopAtShutdown(true);
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
//设置原始 War的位置
webapp.setWar("./master");
server.setHandler(webapp);
server.start();
server.join();</pre>
相当于用 groovy 来做 jetty 的配置了。