美文网首页程序员之家我爱编程Java 杂谈
[Java] Windows/Linux路径不同时,统一war的

[Java] Windows/Linux路径不同时,统一war的

作者: cb9841112785 | 来源:发表于2018-05-26 20:47 被阅读18次

    一、缘由

    在项目开发时,因为运行环境的不同,导致有时得分别为不同的环境,切换配置参数打不同war包。但手工切换配置文件的话,不仅费时费力,而且容易出错。

    有些打包工具支持配置切换。这样我们只要配好有那几组参数,然后便可分别打war包了。但该办法还是存在多个war文件易搞错的问题。而且因为生产环境一般有Windows、Linux 2类操作系统,导致生产环境的war也得分别搞2套,这是否真的有必要。

    所以我们希望能统一war。即仅打包一个war,而该war能在各种环境下运行。

    虽然可以使用“war 配置文件分离”、“将配置参数放到数据库”等办法来实现统一war。但那些办法比较复杂,而且仍会引起配置文件种类过多问题。

    分析了一下 Windows、Linux 不同的配置参数,发现它们一般都是因为路径不同而被迫做成参数配置的。

    于是我针对这种情况,找到了一些简单、有效的处理办法。使它们在Windows、Linux切换时不用更改参数,有利于统一war。

    二、统一路径写法

    2.1 问题

    对于Windows、Linux 不同的配置参数,最常见的是日志文件的路径。例如以下分别是 Linux、Windows 下的日志目录——

    /mysystem/app1/logE:\mysystem\app1\log

    可见,这2种目录的目录结构是类似,仅是因为 Linux、Windows 的路径格式不同,而有了2点差异——

    文件分隔符不同。Linux(等Unix类)系统用斜杠( / ),而Windows系统用反斜杠( \)。

    根目录写法不同。Linux(等Unix类)系统是单根的 / ,而Windows系统有盘符的概念(如E:\ )。

    2.2 办法

    对于操作系统的路径格式区别,我们可以使用 System.getProperty("file.separator")得到文件分隔符,使用 File.listRoots() 得到根目录情况。根据这些信息,我们理论上能写个函数,将约定好格式的路径,给翻译为当前操作系统的路径格式。

    但我后来测试File类时发现,其实有更简单的办法的。

    File类的2点特性,对我们很有用——

    在给File类的构造函数传递 Linux风格的路径时,会自动转为当前系统的文件分隔符。例如传递/mysystem/app1/log ,随后File构造好后实际为 \mysystem\app1\log 。

    在Windows下通过File类打开文件流时,若路径中没有盘符,则会自动选择当前工作目录(user.dir)的盘符。例如对于 \mysystem\app1\log ,假设当前工作目录是E盘,那么实际的路径是 E:\mysystem\app1\log 。

    即File类会自动将 Linux(等Unix类)系统风格的路径,转为Windows风格的路径。只要我们能保证工作目录的所在盘符,就是所需的盘符。

    2.3 应用:logback的日志路径

    2.3.1 之前

    之前在 logback.xml 文件中是这样指定路径的。

    -->

    它默认用Linux的路径参数,而Windows的路径参数是处于被注释的状态。

    然后在需要部署到Windows系统时,调整一下注释使第2行生效,并根据实际情况调整一下盘符。

    2.3.2 之后

    现在 logback.xml 文件中只需写Linux目录就行。

    war包一般是在tomcat等web容器中运行的。对于Windows下,工作目录的盘符就是web容器所在盘符。

    假设该war部署在E盘的tomcat上的,那么配置文件中的 /mysystem/app1/log ,实际上是E:\mysystem\app1\log 。

    假设该war部署在F盘的weblogic上的,那么配置文件中的 /mysystem/app1/log ,实际上是 F:\mysystem\app1\log 。

    ……

    2.4 小结

    统一路径写法是非常简单的,即只保留Linux(Unix类)路径写法就行。这样大多数程序都能正常工作的。

    三、不支持统一路径写法时

    3.1 问题与思路

    有少量程序是不支持统一路径写法的写法(可能是因为它们没有使用File类来处理文件路径,而是手工拼接)。这时该怎么办呢?

    退回之前的“配置切换”法是不行的,容易造成参数复杂等问题。

    因Java中能判断操作系统版本,故可以考虑写个函数,将统一路径写法转为当前操作系统的格式。这样便解决问题了。

    System.getProperty可获取系统属性——

    os.name : 操作系统的名称。例如Windows系统都是以 windows 开头。

    user.dir : 用户的当前工作目录。

    3.2 代码

    /** 判断是不是Windows系统.

        *

        * @return    返回是不是Windows系统.

        */privatestaticbooleanisOsWindows() {Stringosname = System.getProperty("os.name").toLowerCase();booleanrt = osname.startsWith("windows");returnrt;    }/** 将路径修正为当前操作系统所支持的形式.

        *

        * @param path    源路径.

        * @return    返回修正后的路径.

        */publicstaticStringfixPath(Stringpath) {if(null==path)returnpath;if(path.length()>=1&& ('/'==path.charAt(0) ||'\\'==path.charAt(0))) {// 根目录, Windows下需补上盘符.if(isOsWindows()) {Stringuserdir = System.getProperty("user.dir");if(null!=userdir && userdir.length()>=2) {returnuserdir.substring(0,2) + path;                }            }        }returnpath;    }

    于是可利用fixPath函数,将配置中读到的路径,转为当前操作系统的格式。

    四、Linux与Windows下的参数不同时

    4.1 问题与思路

    上面的办法主要是适合于路径结构相同时。可是有些时候,Linux与Windows下的参数不同,例如动态库的路径——

    /mysystem/app1/libMyLib.soE:\mysystem\app1\MyLib.dll

    它们主要是有这2点差异——

    后缀名不同。Linux系统用so,而Windows系统用dll。

    文件基本名的命名习惯不同。Linux系统一般有个“lib”前缀。

    4.2 办法

    假设动态库的文件名都是符合命名规范的话,理论上是可以写个函数将“lib .so”替换为“ .dll”的。但是该办法存在缺点——万一遇到不符合规范的文件名就麻烦了。

    所以建议采用这个办法——在配置文件中分别给出不同操作系统的参数,然后java端判断一下操作系统,选择符合当前操作系统的参数。

    不只是动态库路径,该办法还能推广任何的“Linux与Windows下的参数不同”问题,都可以按此办法来处理。

    随后会遇到一个小问题——这种参数,因不同操作系统会有多个参数名(如 path.MyLib_windows 、 path.MyLib_linux )。当取参数时,若都将这些参数名传过去,代码会变得很臃肿。而且不易扩充操作系统类型。

    所以建议制定一下规范——带“._windows”后缀的是Windows特有参数,否则则是默认参数(Linux的)。这样便简化了参数名传递,且有利于未来增加操作系统的支持。

    代码如下——

    /** 取得字符串_自动选择操作系统的专用参数, 具有 defaultValue 参数.    *    *

          *   
    • 当为Windows时, 优先读取 {@codekey + "._windows"} 参数, 找不到时才用 {@codekey} .
    •     *
        *    *@paramconfig    配置对象.    *@paramkey    的键名.    *@paramdefaultValue    默认值.    *@return返回所找到的参数值, 找不到时返回 defaultValue .    */publicstaticString getString(AbstractConfiguration config, String key, String defaultValue) {        String rt =null;if(isOsWindows()) {            String key2 = key+"._windows";            rt = config.getString(key2,null);        }if(null==rt) {            rt = config.getString(key, defaultValue);        }returnrt;    }/** 取得字符串_自动选择操作系统的专用参数, 无 defaultValue 参数.    *    *
          *   
    • 当为Windows时, 优先读取 {@codekey + "._windows"} 参数, 找不到时才用 {@codekey} .
    •     *
        *    *@paramconfig    配置对象.    *@paramkey    的键名.    *@return返回所找到的参数值, 找不到时返回空串.    */publicstaticString getString(AbstractConfiguration config, String key) {returngetString(config, key,null);    }/** 取得路径字符串_自动选择操作系统的专用参数, 具有 defaultValue 参数. Windows下会自动将根目录(/)转为当前盘符的根路径(E:/) .    *    *
          *   
    • 当为Windows时, 优先读取 {@codekey + "._windows"} 参数, 找不到时才用 {@codekey} .
    •     *
        *    *@paramconfig    配置对象.    *@paramkey    的键名.    *@paramdefaultValue    默认值.    *@return返回所找到的参数值, 找不到时返回 defaultValue .    */publicstaticString getStringPath(AbstractConfiguration config, String key, String defaultValue) {        String rt = getString(config, key, defaultValue);        rt = fixPath(rt);returnrt;    }/** 取得路径字符串_自动选择操作系统的专用参数, 无 defaultValue 参数. Windows下会自动将根目录(/)转为当前盘符的根路径(E:/) .    *    *
          *   
    • 当为Windows时, 优先读取 {@codekey + "._windows"} 参数, 找不到时才用 {@codekey} .
    •     *
        *    *@paramconfig    配置对象.    *@paramkey    的键名.    *@return返回所找到的参数值, 找不到时返回空串.    */publicstaticString getStringPath(AbstractConfiguration config, String key) {returngetStringPath(config, key,null);    }

    4.3 用法

    4.3.1 之前

    之前靠注释来切换所需配置的。

    path.MyLib=/mysystem/app1/libMyLib.so#path.MyLib=E:\mysystem\app1\MyLib.dll

    它默认用Linux的参数,而Windows的参数是处于被注释的状态。

    然后在需要部署到Windows系统时,调整一下注释使第2行生效。(已经利用之前的内容,使用统一路径写法)

    4.3.2 之后

    现在可直接在配置文件中写上这2个参数。注意给Windows版参数加上“._windows”后缀。

    path.MyLib=/mysystem/app1/libMyLib.sopath.MyLib._windows=/mysystem/app1/MyLib.dll

    然后在程序中这样获取配置了。

    String pathMyLib = getStringPath(config,"path.MyLib");

    随后war运行时,会自动根据当前操作系统,选取自己的参数。 保证了war包的统一。

    五、总结

    回想一下本文的办法,它其实是“约定大于配置”思想的一种实践。

    相关文章

      网友评论

        本文标题:[Java] Windows/Linux路径不同时,统一war的

        本文链接:https://www.haomeiwen.com/subject/arcvjftx.html