我们开发java应用程序后,发布为jar可执行文件时,会把resources里的配置文件一同发布到jar文件里,不利于将来的配置修改,下面是我的jar读起外部配置文件的方法:
适用范围:eclipse或者sts创建的普通maven应用程序,不是web项目,也不是spring项目。
jar文件和resources配置文件夹在同一个目录下;不在同一个目录则程序代码做响应的修改;
步骤:
创建项目
file–new–Maven Project,maven-archetype-quickstart…
项目目录结构如图:
项目涉及读取的配置文件有log4j.properties:log4j日志功能的配置文件;
redis.properties:redis缓存功能的配置文件;
dbconfigration.xml:mysql数据库/mybatis持久层框架的配置文件;
还有就是应用程序的项目信息配置文件;
而model下的member.xml则是的mapper配置文件;
下面是应用程序发布成jar文件后的目录结构:
就是有一个jar文件和一个resources文件夹,resources里面是之前的配置文件,当然,这个resources文件夹是手动copy过来跟.jar文件同一个目录的。
为了能在jar运行后能够读起它外部resources里的配置文件,我要在程序上做处理:
首先处理log4j配置文件的的读取,为了能够让log4j引用外部resources里的配置文件,我们要在应用程序运行初期指定log4j配置文件路径,如在main里指定log4j的配置文件路径:
String userdir = MyPath.getProjectPath();//获取应用程序的根路径,重点
String logconfigfile = userdir + File.separatorChar + “resources” + File.separatorChar + “log4j.properties”;//获取配置文件的物理路径,这就是外部路径
try {
File file = new File(“log4j.properties”);//读起配置文件
if (!file.exists()) {
file = new File(logconfigfile);
if (file.exists())
// 配置文件初始化
PropertyConfigurator.configure(logconfigfile);
else {
logconfigfile = userdir + File.separatorChar + “src” + File.separator + “main” + File.separator
+ “resources” + File.separatorChar + “log4j.properties”;//这是内部路径,为了在开发工具(sts/eclipse)里能够运行
file = new File(logconfigfile);
if (file.exists())
// 配置文件初始化
PropertyConfigurator.configure(logconfigfile);
}
System.out.println(“configfile log4j complete:” + logconfigfile);
}
} catch (Exception e) {
System.out.println(“configfile log4j fail”);
}
这样就完成了log4j的配置文件指定;
下面贴出
MyPath类的实现代码(转载+测试):
publicclass MyPath {
publicstatic String getProjectPath() {
java.net.URL url = MyPath.class.getProtectionDomain().getCodeSource().getLocation();
String filePath = null;
try {
filePath = java.net.URLDecoder.decode(url.getPath(), “utf-8”);
} catch (Exception e) {
e.printStackTrace();
}
if (filePath.endsWith(“.jar”))
filePath = filePath.substring(0, filePath.lastIndexOf(“/”) + 1);
java.io.File file = new java.io.File(filePath);
filePath = file.getAbsolutePath();
return filePath;
}
publicstatic String getRealPath() {
String realPath =“”;
try
{
realPath = MyPath.class.getClassLoader().getResource(“”).getFile();
}
catch(Exception ec)
{
returnnull;
}
java.io.File file = new java.io.File(realPath);
realPath = file.getAbsolutePath();
try {
realPath = java.net.URLDecoder.decode(realPath, “utf-8”);
} catch (Exception e) {
e.printStackTrace();
}
return realPath;
}
publicstatic String getAppPath(Class> cls) {
// 检查用户传入的参数是否为空
if (cls == null)
thrownew java.lang.IllegalArgumentException(“参数不能为空!”);
ClassLoader loader = cls.getClassLoader();
// 获得类的全名,包括包名
String clsName = cls.getName();
// 此处简单判定是否是Java基础类库,防止用户传入JDK内置的类库
if (clsName.startsWith(“java.”) || clsName.startsWith(“javax.”)) {
thrownew java.lang.IllegalArgumentException(“不要传送系统类!”);
}
// 将类的class文件全名改为路径形式
String clsPath = clsName.replace(“.”, “/”) + “.class”;
// 调用ClassLoader的getResource方法,传入包含路径信息的类文件名
java.net.URL url = loader.getResource(clsPath);
// 从URL对象中获取路径信息
String realPath = url.getPath();
// 去掉路径信息中的协议名”file:”
int pos = realPath.indexOf(“file:”);
if (pos > -1) {
realPath = realPath.substring(pos + 5);
}
// 去掉路径信息最后包含类文件信息的部分,得到类所在的路径
pos = realPath.indexOf(clsPath);
realPath = realPath.substring(0, pos – 1);
// 如果类文件被打包到JAR等文件中时,去掉对应的JAR等打包文件名
if (realPath.endsWith(“!”)) {
realPath = realPath.substring(0, realPath.lastIndexOf(“/”));
}
java.io.File file = new java.io.File(realPath);
realPath = file.getAbsolutePath();
try {
realPath = java.net.URLDecoder.decode(realPath, “utf-8”);
} catch (Exception e) {
thrownew RuntimeException(e);
}
return realPath;
}// getAppPath定义结束
}
其中,getRealPath的
realPath = MyPath.class.getClassLoader().getResource(“”).getFile();
在执行java -jar xxx.jar时将出错,也就是说这个方法在本案中不可用。
下面讲一下读起mybatis的配置文件dbconfiguration.xml的方法:
static {
try {
String dbconfigfile = “dbconfigration.xml”;
File file = new File(dbconfigfile);
if (file.exists() && !file.isDirectory())
reader = new FileReader(dbconfigfile);//开发环境运行
// Resources.getResourceAsReader(dbconfigfile);
else {
String userdir = MyPath.getProjectPath();
//发布后环境运行读取路径
dbconfigfile = userdir + File.separatorChar + “resources” + File.separatorChar + dbconfigfile;
System.out.println(“dbconfig.xml filepath:” + dbconfigfile);
file = new File(dbconfigfile);
if (file.exists() && !file.isDirectory())
reader = new FileReader(dbconfigfile);
else
{
//开发环境运行路径
dbconfigfile = userdir + File.separatorChar + “src” + File.separator + “main” + File.separator+ “resources” + File.separatorChar + dbconfigfile;
System.out.println(“dbconfig.xml filepath:” + dbconfigfile);
file = new File(dbconfigfile);
if (file.exists() && !file.isDirectory())
reader = new FileReader(dbconfigfile);
else
{
System.out.println(“dbconfile is no found”);
}
}
}
if (reader != null)
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
else {
System.out.println(“dbconfig reader is null”);
}
} catch (IOException e) {
e.printStackTrace();
}
}
上面的程序的作用就是获得mybatis配置文件xml的正确的reader,从而通过sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);来初始化mybatis的session;
我们来看看dbconfigration.xml的内容,
/p>
PUBLIC “-//http://mybatis.org//DTD Config 3.0//EN”
–>
–>
–>
value=“jdbc:mysql://localhost:3306/dbname?characterEncoding=utf-8&useSSL=true” />
其中这里用”resource”指向member.xml文件,这在.jar发布后,将无法读起,其实mapper还有可以以url的方式配置mapper配置文件:
这里file就可以根据实际路径进行配置了。
这样,mybatis的配置和映射配置就没有问题了;
下面我们来看一下读取外部普通.properties配置文件的方法
读取配置文件,可以通过获取文件的inputstream流,我们首先写一个通用的类来获取正确的配置文件的inoutstream流,其主要方法如下:
publicstatic InputStream getConfigStream(String filename)
{
// 配置文件初始化
//PropertyConfigurator.configure(filepath);
InputStream inputStream = null;
try {
inputStream = Config.class.getClassLoader().getResourceAsStream(filename);//为了开发环境能够运行
if (inputStream ==null)
{
String userdir = MyPath.getProjectPath();
String configfile = userdir + File.separatorChar + “resources” +File.separatorChar +filename;//获取外部配置文件路径
System.out.println(“getConfigProperties configfilepath:” + configfile);
inputStream = new FileInputStream(configfile);//获取配置文件的流
if (inputStream ==null )
{
System.out.println(“tc.properties is not found”);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return inputStream;
}
有了正确的配置文件的inputstream后,就可以用property来读取这个流了;
String tcconfigfile = “cofig.properties”;
InputStream in = getConfigStream(tcconfigfile);//获取正确的流
if (in != null) {
Properties property = new Properties();
property.load(in);
String configPort = property.getProperty(“socket.port”);
in.close(); in=null;
if (configPort != null && configPort != “”) {
System.out.println(“socket.port:” + configPort);
port = Integer.parseInt(configPort);
} else
{
System.out.println(“server port readfail!”);
}
} else {
port = 5880;
}
注意:jar文件和resources配置文件夹在同一个目录下;不在同一个目录则程序代码做响应的修改;
补充:jar的导出方法,右键项目--export--java(Runnable JAR file)–lanuch configuration选择你的项目,再Export destination设置你的jar导出路径,Library handing:选extract required libraries into generation JAR–Finish , 完成;
执行jar: java -jar /jarfilepath/jarfilename.jar
如果你的jar是一个服务,要让他在后台运行,那么,可以用下面的脚本(linux和mac里可用):
#! /bin/sh
#启动方法
start(){
now=`date “+%Y%m%d%H%M%S”`
exec java -Xms128m -Xmx2048m -jar /Users/username/Desktop/java/20170318/jarfile.jar >’log/tclog/'”$now”_bidcheck.log &
}
#停止方法
stop(){
ps -ef|grep java|awk ‘{print $2}’|while read pid
do
kill -9 $pid
done
}
case “$1” in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
printf ‘Usage: %s {start|stop|restart}\n’ “$prog”
exit 1
;;
esac
把上面的脚本保存成servcejar.sh,启动方法就是:
sh servcejar.sh start
还有
sh servcejar.sh restart
sh servcejar.sh stop
本文完;