将 Groovy 融入项目的部署过程
札记    无    2016-11-03 00:18:53    305    0    0

配置文件的编写一直都是个烦心事。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 的配置了。

文档导航