背景
java应用,不管是web还是jar程序,读取配置文件始终是绕不过去的。
一开始没那么多弯弯绕绕,反正什么配置文件,完全打包就完事,读取也是相对路径,IDE能跑,部署到服务器也不会有问题。
然后,如果要提升部署的质量,满足运维的要求,那就没那么简单了。比如我们可能面临:
1、部署到Tomcat?springboot的jar进程部署?
2、配置文件需要从jar里面拉出来,方便部署时修改配置
主题
本文的主题就是配置文件的读取
首先直接上例子(几种常用读取路径的区别)
public class ServerPath {
public static void main(String[] args) {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
System.out.println("ClassLoader mode = " + loader.getResource("").getPath());
System.out.println("class.getResource'' mode = " + ServerPath.class.getResource("").getPath());
System.out.println("class.getResource'/' mode = " + ServerPath.class.getResource("/").getPath());
System.out.println("System.getProperty(\"user.dir\") mode = " + System.getProperty("user.dir"));
}
}
执行结果(两个操作系统环境)
结论:
1、loader.getResource("").getPath() 和 ServerPath.class.getResource("/").getPath() 结果是一样的,都是得到 classpath (classpath
是JVM用到的一个环境变量,它用来指示JVM如何搜索class
。)
2、ServerPath.class.getResource("").getPath() 得到的是执行类的完整路径
3、System.getProperty("user.dir") 得到的是基于当前用户的执行程序的文件路径
一般情况下,我们只需要用到classpath,毕竟很多配置路径缺省的情况下都是相对于classpath 去读取的,如果都改成绝对路径,代价太大,也容易出错。
围绕这点,进阶!
进阶
1、spring 配置加载application.yml文件顺序
springboot启动会扫描一下位置的application.properties或者application.yml作为默认的配置文件 工程根目录:./config/ 工程根目录:./ classpath:/config/ classpath:/ 加载的优先级顺序是从上向下加载,并且所有的文件都会被加载(后面的不会覆盖同名的前面配置)
2、执行jar 指定额外的classpath
java -Xbootclasspath/a:具体路径 -jar my.jar
基于以上配置(保证前两步的配置正常)的配置文件读取,以下各种场景皆可正常使用
我这里使用的是 java -Xbootclasspath/a:. -jar my.jar
场景
1、入口程序的 ApplicationContext.xml 配置加载
2、log4j配置文件加载
@ImportResource("classpath:config/spring/webApplicationContext.xml")
@EnableJpaRepositories
public class WebApplication {
public static void main(String[] args) {
System.out.println("classpath =" + SpringApplication.class.getResource("/").getPath());
// 日志配置
URL logConfigURL = WebApplication.class.getResource("/config/properties/log4j.properties");
PropertyConfigurator.configure(logConfigURL);
SpringApplication.run(WebApplication.class, args);
}
}
3、ApplicationContext.xml 其他配置引用
<import resource="classpath*:/config/spring/redisConnect.xml"/>
<import resource="classpath*:/config/spring/mongodbConnect.xml"/>
<context:property-placeholder location="classpath*:/config/properties/*.properties"/>
4、程序内部读取配置文件
ClassPathResource c = new ClassPathResource("config/properties/test.properties");
EncodedResource encodedResource = new EncodedResource(c, StandardCharsets.UTF_8);
Properties properties = PropertiesLoaderUtils.loadProperties(encodedResource);
5、通过注解读取配置文件以及配置项
@Component
@PropertySource("classpath:config/properties/test.properties")
public class MyConfig {
/** 用户名 */
@Value("${userName}")
private String userName;
}
高级
1、配置文件位置任意定 (以上已实现,启动指定加载classpath,项目内部使用相对classpath的方式读取配置)
2、启动服务命令可以在任意目录执行
知识点包括:自定义启动jar ; 使用绝对路径读取启动项 ; 自动创建日志目录 ; 启动后自动打印日志 ;重复启动可选是否重启
以下是startup.sh内容:
# absolute-path
path=$(dirname `readlink -f $0`)
echo ${path}
name=$path/my.jar
build_dir=$path"/logs"
if [ ! -d "$build_dir" ]; then
mkdir $build_dir
fi
pid=`ps -ef | grep $name| grep -v grep |awk '{print $2}'`
if [ $pid ]; then
echo ${name} is running pid=$pid
read -r -p "restart the server? [y/n] " input
case $input in
[yY][eE][sS]|[yY])
kill -9 $pid
echo restart ${name}......
sleep 3
nohup java -Xbootclasspath/a:$path -jar -Xms128m -Xmx128m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m $name >>logs/info.log &
tail -f $path/logs/info.log
;;
[nN][oO]|[nN])
echo "No"
exit 1
;;
*)
echo "Invalid input Please enter [y/n]"
echo ""
exit 1
;;
esac
else
nohup java -Xbootclasspath/a:. -jar -Xms128m -Xmx128m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m $name >>logs/info.log &
tail -f $path/logs/info.log
fi
3、以上基于一定的打包策略
① 所有依赖的jar 在当前目录的 lib
② 配置文件放在 在当前目录的 config
③启动配置 application.yml在当前目录
其他需要的细节请参考:
Springboot 项目 maven 打包不包含第三方jar包
Spring boot 项目打包 + Linux 部署 / maven jar项目打包部署到Linux/ start.sh