作者: zyl910

一、缘由

在项目开发时,因为运行环境的不同,导致有时得分别为不同的环境,切换配置参数打不同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/log
E:\mysystem\app1\log

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

  1. 文件分隔符不同。Linux(等Unix类)系统用斜杠(/),而Windows系统用反斜杠(\)。
  2. 根目录写法不同。Linux(等Unix类)系统是单根的 /,而Windows系统有盘符的概念(如 E:\)。

2.2 办法

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

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

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

  1. 在给File类的构造函数传递 Linux风格的路径时,会自动转为当前系统的文件分隔符。例如传递 /mysystem/app1/log,随后File构造好后实际为 \mysystem\app1\log
  2. 在Windows下通过File类打开文件流时,若路径中没有盘符,则会自动选择当前工作目录(user.dir)的盘符。例如对于 \mysystem\app1\log,假设当前工作目录是E盘,那么实际的路径是 E:\mysystem\app1\log

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

2.3 应用:logback的日志路径

2.3.1 之前

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

<property name="LOG_HOME" value="/mysystem/app1/log" />
<!-- <property name="LOG_HOME" value="E:\mysystem\app1\log" /> -->

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

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

2.3.2 之后

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

<property name="LOG_HOME" value="/mysystem/app1/log" />

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系统.
*/
private static boolean isOsWindows() {
String osname = System.getProperty("os.name").toLowerCase();
boolean rt = osname.startsWith("windows");
return rt;
} /** 将路径修正为当前操作系统所支持的形式.
*
* @param path 源路径.
* @return 返回修正后的路径.
*/
public static String fixPath(String path) {
if (null==path) return path;
if (path.length()>=1 && ('/'==path.charAt(0) || '\\'==path.charAt(0))) {
// 根目录, Windows下需补上盘符.
if (isOsWindows()) {
String userdir = System.getProperty("user.dir");
if (null!=userdir && userdir.length()>=2) {
return userdir.substring(0, 2) + path;
}
}
}
return path;
}

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

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

4.1 问题与思路

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

/mysystem/app1/libMyLib.so
E:\mysystem\app1\MyLib.dll

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

  1. 后缀名不同。Linux系统用so,而Windows系统用dll。
  2. 文件基本名的命名习惯不同。Linux系统一般有个“lib”前缀。

4.2 办法

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

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

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

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

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

代码如下——

    /** 取得字符串_自动选择操作系统的专用参数, 具有 defaultValue 参数.
*
* <ul>
* <li>当为Windows时, 优先读取 {@code key + "._windows"} 参数, 找不到时才用 {@code key} .</li>
* </ul>
*
* @param config 配置对象.
* @param key 的键名.
* @param defaultValue 默认值.
* @return 返回所找到的参数值, 找不到时返回 defaultValue .
*/
public static String 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);
}
return rt;
} /** 取得字符串_自动选择操作系统的专用参数, 无 defaultValue 参数.
*
* <ul>
* <li>当为Windows时, 优先读取 {@code key + "._windows"} 参数, 找不到时才用 {@code key} .</li>
* </ul>
*
* @param config 配置对象.
* @param key 的键名.
* @return 返回所找到的参数值, 找不到时返回空串.
*/
public static String getString(AbstractConfiguration config, String key) {
return getString(config, key, null);
} /** 取得路径字符串_自动选择操作系统的专用参数, 具有 defaultValue 参数. Windows下会自动将根目录(/)转为当前盘符的根路径(E:/) .
*
* <ul>
* <li>当为Windows时, 优先读取 {@code key + "._windows"} 参数, 找不到时才用 {@code key} .</li>
* </ul>
*
* @param config 配置对象.
* @param key 的键名.
* @param defaultValue 默认值.
* @return 返回所找到的参数值, 找不到时返回 defaultValue .
*/
public static String getStringPath(AbstractConfiguration config, String key, String defaultValue) {
String rt = getString(config, key, defaultValue);
rt = fixPath(rt);
return rt;
} /** 取得路径字符串_自动选择操作系统的专用参数, 无 defaultValue 参数. Windows下会自动将根目录(/)转为当前盘符的根路径(E:/) .
*
* <ul>
* <li>当为Windows时, 优先读取 {@code key + "._windows"} 参数, 找不到时才用 {@code key} .</li>
* </ul>
*
* @param config 配置对象.
* @param key 的键名.
* @return 返回所找到的参数值, 找不到时返回空串.
*/
public static String getStringPath(AbstractConfiguration config, String key) {
return getStringPath(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.so
path.MyLib._windows=/mysystem/app1/MyLib.dll

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

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

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

五、总结

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

(完)

参考文献

[Java] Windows/Linux路径不同时,统一war的最简办法的更多相关文章

  1. python复制文件,路径不存在问题(Windows和linux路径分隔符不统一)

    问题: python脚本涉及到复制文件,而我们需要兼容Windows.linux和mac环境 (Windows和linux的路径分隔符不同:通过os.path.sep查看分隔符)   如果用[路径名+ ...

  2. paip兼容windows与linux的java类根目录路径的方法

    paip兼容windows与linux的java类根目录路径的方法 1.只有 pathx.class.getResource("")或者pathx.class.getResourc ...

  3. Java中windows路径转换成linux路径等工具类

    项目中发现别人写好的操作系统相关的工具类: 我总结的类似相关博客:http://www.cnblogs.com/DreamDrive/p/4289860.html import java.net.In ...

  4. Java ssh 访问windows/Linux

     Java ssh 访问windows/Linux 工作中遇到的问题: Java code运行在一台机器上,需要远程到linux的机器同时执行多种命令.原来采用的方法是直接调用ssh命令或者调用pli ...

  5. Windows文件路径转换为java中可识别的文件路径的转义方法,(另附转义多种格式)

    ps:欢迎加qq好友:2318645572,交流学习 一:路径转化 Windows中的文件路径格式为 D:\eclipse\apache-tomcat-7.0.67\wtpwebapps\... Ja ...

  6. linux 查看java的安装路径

    在linux下,如何找java的安装路径 han@ubuntu:/etc$ whereis java java: /usr/bin/java /usr/share/java /usr/lib/jvm/ ...

  7. java工具类,在Windows,Linux系统获取电脑的MAC地址、本地IP、电脑名

    package com.cloudssaas.util; import java.io.BufferedReader; import java.io.IOException; import java. ...

  8. Windows/Linux下引用jar包,并用javac/java编译运行

    Windows/Linux下引用jar包,并用javac/java编译运行,有需要的朋友可以参考下. 1> Windows 假设要引用的jar放在D:/test目录下,名字为t1.jar, ja ...

  9. Windows/Linux javac/java编译运行引入所需的jar包

    > Windows 假设要引用的jar放在D:/test目录下,名字为t1.jar, java源文件放在D:/test/src目录下,名字为t2.java. 编译: javac  -cp  d: ...

随机推荐

  1. 简单的使用Nginx框架搭建Web服务器~

    系统环境Debian 8,内核版本 一.首先来安装nginx服务程序:  1.安装nginx服务需要的相关程序(记得在root权限下操作下面的指令) aptitude install libpcre3 ...

  2. POJ 2594 Treasure Exploration (Floyd+最小路径覆盖)

    <题目链接> 题目大意: 机器人探索宝藏,有N个点,M条边.问你要几个机器人才能遍历所有的点. 解题分析: 刚开始还以为是最小路径覆盖的模板题,但是后面才知道,本题允许一个点经过多次,这与 ...

  3. pacman 命令

    安装 pacman -S  删除 pacman -R  移除已安装不需要软件包 pacman -Rs  删除一个包,所有依赖 pacman -Rsc  升级包 pacman -Syu  查询包数据库 ...

  4. 学习笔记——在vue中如何配置Jest(一)

    最近在搞Jest单元测试,如何在vue中安装和使用jest我就不说了,前一篇文章简单的说了一下在使用jest时遇到的一些问题,但是我觉得并没有真正的解决的很好.后面会在学习过程中更新前面的那篇文章,加 ...

  5. Django 学习第九天——请求与响应

    一.HttpRequest 对象: 服务器接收到http协议的请求后,会根据报文创建 HttpRequest 对象视图函数的第一个参数是HttpRequest 对象再django.http 模块中定义 ...

  6. DevOps: CLM, RLM, RPM, RPD, BSA, BAA, BMA - WOW!

    1. BMC Release Lifecycle Management (RLM) is our suite targeted at managing and automating applicati ...

  7. java validate date

    public boolean isDateValidDDMMYYYY(String date) { String DATE_FORMAT = "ddMMyyyy"; try { D ...

  8. 利用cookie实现iframe刷新时停留在当前页面

    这段时间第一次用iframe,发现问题还挺多,这次主要解决了一个用cookie实现iframe刷新时停留在当前页面,具体步骤如下: 1.必须在每一个页面中记录下当前的url并存入cookie中,具体代 ...

  9. fluxion-wifi破解/钓鱼

    转载内容,侵删 https://bbs.ichunqiu.com/thread-24085-1-5.html     0x00前言:         有人说我比那些收费的平台更可恨,因为我写教程不收费 ...

  10. MySQL分页limit速度太慢的优化方法

    limit用法 在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,这个时候怎么办呢?不用担心,mysql已经为我们提供了这样一个功能. SELECT * FROM table LIMIT ...