打包成fatjar后,log4j 配置文件加载不到

打包后的目录结构如下:

image.png

log4j.properties 是放在config目录下面的,fatjar打包的时候排除了log4j.properties。

启动的时候报找不到logger:

Starting JFinal 4.3 -> http://0.0.0.0:80
Info: jfinal-undertow 1.7, undertow 2.0.22.Final, jvm 1.8.0_211
log4j:WARN No appenders could be found for logger (org.jboss.logging).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Starting Complete in 0.9 seconds. Welcome To The JFinal World (^_^)

打包成fatjar日志配置应该怎么加载呢?

评论区

JFinal

2019-08-20 20:38

用 winrar 打开 jar 包看看里头有没有 log4j.properties

jar 包中的配置文件被加载的优先级始终高于 config 目录下面

既然你都有 config 目录了,建议不要打成 fatjar

如果一定要打成 fatjar ,将 log4j.properties 中的配置改好以后再打包,多省事

JFinal

2019-08-20 20:39

总结就是: 需要改配置就不要打 fatjar , 否则 "非 fatjar" 更方便,因为这种模式的目录并不多,文件也不多

新手的呐喊

2019-08-21 08:44

@JFinal fatjar里面没有log4j.properties。打成fatjar主要想是所有的依赖包可以打成一个jar包,部署的时候只copy一个jar包,增量部署的时候不用考虑是不是有新增的依赖。因为是纯接口项目,所以webapp只是用来上传文件用的,没有copy的必要。另外,我是想把配置和应用程序完全分开的,所以应用程序里除了sql模板,不包含任何配置文件。
我之前以为是把config目录附加到classpath里面去了,但是把log4j的配置文件放在config里好像加载不到。。。

新手的呐喊

2019-08-21 08:52

我测试了一下:
log4j的classloader是 classloader:sun.misc.Launcher$AppClassLoader@5c647e05
Prop的classloader是classloader:com.jfinal.server.undertow.hotswap.HotSwapClassLoader@4524411f
应该是因为这个所以log4j的配置文件加载不到

新手的呐喊

2019-08-21 09:22

最后用了这种hack的方式解决了。。。。。。。。
ClassLoaderKit classLoaderKit = new ClassLoaderKit(PropExt.class.getClassLoader(), null);
PropertyConfigurator.configure(classLoaderKit.getClassLoader().getResource("log4j.properties"));
UndertowServer.start(AppConfig.class);

chcode

2019-08-21 19:46

@新手的呐喊 每次一个zip到服务器上解压不是更方便

happyboy

2019-08-22 10:25

@chcode 如果你经常做运维,你会发现其实这样很不方便,尤其是当项目很大,网络又很慢的时候。

JFinal

2019-08-22 16:13

@新手的呐喊 其实 jfinal 的默认打包方式已经足够方便了,文件并不多,所有的 class 文件也打成了 jar 包

fatjar 还是建议啥配置都不用改的情况下使用。 为此,jfinal-undertow 还提供了命令行传参的方式来启动,注意看下面代码的第 188 行:
https://gitee.com/jfinal/jfinal-undertow/blob/jfinal-undertow-1.9/src/main/java/com/jfinal/server/undertow/UndertowServer.java

命令行可以这样用:
java -Dundertow.port=8080 -Dundertow.host=0.0.0.0 -jar my-project.jar

另外还有三个参数也可以这样来传递,也就是说,fatjar 的用法已经将常用的参数可以在配置文件之外优先传递了

这些努力都是为了让你在使用 fatjar 时不必再改配置文件,更不必去添加 config 目录

新手的呐喊

2019-08-22 16:16

@chcode 因为测试环境和生产环境的配置不同啊,不能直接解压覆盖。如果每次都拷贝整个zip的,需要额外做一些解压合并的工作,这样的话,就不方便做自动化了。通过将配置和应用分离,配置通过统一配置中心去获取,应用程序通过CI服务器获取,就可以在很大程序上实现自动化运维了。理想状态的话,就可以实现鼠标点击一个按钮,就可以将选中版本的应用程序以选中的配置,部署到指定的机器上。

新手的呐喊

2019-08-22 16:23

@JFinal 嗯嗯,是的,jfinal的配置本来就是非常方便了,无奈log4j的配置文件我想放到外面,修改日志级别比较方便。

JFinal

2019-08-22 16:41

@新手的呐喊 如果 jar 包内没有 log4j.properties 文件,而是放在 config 目录下面的话,应该是可以被加载的,除非 log4j 加载配置用了不一样的 ClassLoader

你在前面谈到用的是 log4j的classloader是 sun.misc.Launcher.AppClassLoader,正常情况下是不应该的

或许是 log4j 自己有代码去拿了这个 parent class loader

jfinal 为其它配置文件的加载做过测试,是可以从 config 目录下去拿的, log4j.properties 文件没有做过这个测试

新手的呐喊

2019-08-22 16:54

@JFinal Log4j的源码里面是一个static块自己去加载的,优先取的Thread Context Loader ,取不到话就去取自身的class.getClassLoader()。