博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
gradle项目中资源文件的相对路径打包处理技巧
阅读量:6806 次
发布时间:2019-06-26

本文共 9253 字,大约阅读时间需要 30 分钟。

开发java application时,不管是用ant/maven/gradle中的哪种方式来构建,通常最后都会打包成一个可执行的jar包程序,而程序运行所需的一些资源文件(配置文件),比如jdbc.properties, log4j2.xml,spring-xxx.xml这些,可以一起打包到jar中,程序运行时用类似classpath*:xxx.xml的去加载,大多数情况下,这样就能工作得很好了。

但是,如果有一天,需要修正配置,比如:一个应用上线初期,为了调试方便,可能会把log的日志级别设置低一些,比如:INFO级别,运行一段时间稳定以后,只需要记录WARN或ERROR级别的日志,这时候就需要修改log4j2.xml之类的配置文件,如果把配置文件打包在jar文件内部,改起来就比较麻烦,要把重新打包部署,要么在线上,先用jar命令将jar包解压,改好后,再打包回去,比较繁琐。

面对这种需求,更好的方式是把配置文件放在jar文件的外部相对目录下,程序启动时去加载相对目录下的配置文件,这样改起来,就方便多了,下面演示如何实现:(以gradle项目为例)

主要涉及以下几点:

1、如何不将配置文件打包到jar文件内

既然配置文件放在外部目录了,jar文件内部就没必要再重复包含这些文件了,可以修改build.gradle文件,参考下面这样:

processResources {    exclude { "**/*.*" }}

相当于覆盖了默认的processResouces task,这样gradle打包时,资源目录下的任何文件都将排除。

2、log4j2的配置加载处理

log4j2加载配置文件时,默认情况下会找classpath下的log4j2.xml文件,除非手动给它指定配置文件的位置,分析它的源码,可以找到下面这段:org.apache.logging.log4j.core.config.ConfigurationFactory.Factory#getConfiguration(java.lang.String, java.net.URI)

1 public Configuration getConfiguration(final String name, final URI configLocation) { 2  3             if (configLocation == null) { 4                 final String configLocationStr = this.substitutor.replace(PropertiesUtil.getProperties() 5                         .getStringProperty(CONFIGURATION_FILE_PROPERTY)); 6                 if (configLocationStr != null) { 7                     ConfigurationSource source = null; 8                     try { 9                         source = getInputFromUri(NetUtils.toURI(configLocationStr));10                     } catch (final Exception ex) {11                         // Ignore the error and try as a String.12                         LOGGER.catching(Level.DEBUG, ex);13                     }14                     if (source == null) {15                         final ClassLoader loader = LoaderUtil.getThreadContextClassLoader();16                         source = getInputFromString(configLocationStr, loader);17                     }18                     if (source != null) {19                         for (final ConfigurationFactory factory : getFactories()) {20                             final String[] types = factory.getSupportedTypes();21                             if (types != null) {22                                 for (final String type : types) {23                                     if (type.equals("*") || configLocationStr.endsWith(type)) {24                                         final Configuration config = factory.getConfiguration(source);25                                         if (config != null) {26                                             return config;27                                         }28                                     }29                                 }30                             }31                         }32                     }33                 } else {34                     for (final ConfigurationFactory factory : getFactories()) {35                         final String[] types = factory.getSupportedTypes();36                         if (types != null) {37                             for (final String type : types) {38                                 if (type.equals("*")) {39                                     final Configuration config = factory.getConfiguration(name, configLocation);40                                     if (config != null) {41                                         return config;42                                     }43                                 }44                             }45                         }46                     }47                 }48             } else {49                 // configLocation != null50                 final String configLocationStr = configLocation.toString();51                 for (final ConfigurationFactory factory : getFactories()) {52                     final String[] types = factory.getSupportedTypes();53                     if (types != null) {54                         for (final String type : types) {55                             if (type.equals("*") || configLocationStr.endsWith(type)) {56                                 final Configuration config = factory.getConfiguration(name, configLocation);57                                 if (config != null) {58                                     return config;59                                 }60                             }61                         }62                     }63                 }64             }65 66             Configuration config = getConfiguration(true, name);67             if (config == null) {68                 config = getConfiguration(true, null);69                 if (config == null) {70                     config = getConfiguration(false, name);71                     if (config == null) {72                         config = getConfiguration(false, null);73                     }74                 }75             }76             if (config != null) {77                 return config;78             }79             LOGGER.error("No log4j2 configuration file found. Using default configuration: logging only errors to the console.");80             return new DefaultConfiguration();81         }
View Code

其中常量CONFIGURATION_FILE_PROPERTY的定义为:

public static final String CONFIGURATION_FILE_PROPERTY = "log4j.configurationFile";
View Code

从这段代码可以看出,只要在第一次调用log4j2的getLogger之前设置系统属性,将其指到配置文件所在的位置即可。

3、其它一些配置文件(比如spring配置)的相对路径加载

这个比较容易,spring本身就支持从文件目录加载配置的能力。

综合以上分析,可以封装一个工具类:

1 import org.springframework.context.ConfigurableApplicationContext; 2 import org.springframework.context.support.FileSystemXmlApplicationContext; 3  4 import java.io.File; 5  6  7 public class ApplicationContextUtil { 8  9     private static ConfigurableApplicationContext context = null;10 11     private static ApplicationContextUtil instance = null;12 13     public static ApplicationContextUtil getInstance() {14         if (instance == null) {15             synchronized (ApplicationContextUtil.class) {16                 if (instance == null) {17                     instance = new ApplicationContextUtil();18                 }19             }20         }21         return instance;22     }23 24     public ConfigurableApplicationContext getContext() {25         return context;26     }27 28     private ApplicationContextUtil() {29 30     }31 32 33     static {34 35         //加载log4j2.xml36         String configLocation = "resources/log4j2.xml";37         File configFile = new File(configLocation);38         if (!configFile.exists()) {39             System.err.println("log4j2 config file:" + configFile.getAbsolutePath() + " not exist");40             System.exit(0);41         }42         System.out.println("log4j2 config file:" + configFile.getAbsolutePath());43 44         try {45             //注:这一句必须放在整个应用第一次LoggerFactory.getLogger(XXX.class)前执行46             System.setProperty("log4j.configurationFile", configFile.getAbsolutePath());47         } catch (Exception e) {48             System.err.println("log4j2 initialize error:" + e.getLocalizedMessage());49             System.exit(0);50         }51 52         //加载spring配置文件53         configLocation = "resources/spring-context.xml";54         configFile = new File(configLocation);55 56         if (!configFile.exists()) {57             System.err.println("spring config file:" + configFile.getAbsolutePath() + " not exist");58             System.exit(0);59         }60 61         System.out.println("spring config file:" + configFile.getAbsolutePath());62 63         if (context == null) {64             context = new FileSystemXmlApplicationContext(configLocation);65             System.out.println("spring load success!");66         }67 68     }69 70 71 }
View Code

注:这里约定了配置文件放在相对目录resources下,而且log4j2的配置文件名为log4j2.xml,spring的入口配置文件为spring-context.xml(如果不想按这个约定来,可参考这段代码自行修改)

有了这个工具类,mainclass入口程序上可以这么用:

1 import org.slf4j.Logger; 2 import org.slf4j.LoggerFactory; 3 import org.springframework.context.ApplicationContext; 4  5 /** 6  * Created by yangjunming on 12/15/15. 7  * author: yangjunming@huijiame.com 8  */ 9 public class App {10 11     private static ApplicationContext context;12     private static Logger logger;13 14 15     public static void main(String[] args) {16 17         context = ApplicationContextUtil.getInstance().getContext();18         logger = LoggerFactory.getLogger(App.class);19 20         System.out.println("start ...");21 22         logger.debug("debug message");23 24         logger.info("info message");25 26         logger.warn("warn message");27 28         logger.error("error message");29 30         System.out.println(context.getBean(SampleObject.class));31 32     }33 }
View Code

再次友情提醒:logger的实例化,一定要放在ApplicationContextUtil.getInstance().getContext();之后,否则logger在第一次初始化时,仍然尝试会到classpath下去找log4j2.xml文件,实例化之后,后面再设置系统属性就没用了。 

4、gradle 打包的处理

代码写完了,还有最后一个工作没做,既然配置文件不打包到jar里了,那就得复制到jar包的相对目录resources下,可以修改build.gradle脚本,让计算机处理处理,在代替手动复制配置文件。

task pack(type: Copy, dependsOn: [clean, installDist]) {    sourceSets.main.resources.srcDirs.each {        from it        into "$buildDir/install/$rootProject.name/bin/resources"    }}

增加这个task后,直接用gradle pack 就可以实现打包,并自动复制配置文件到相对目录resources目录下了,参考下图:

最后国际惯例,给个示例源码:

gradle pack 后,可进入build/install/config-load-demo/bin 目录,运行./config-load-demo (windows下运行config-load-demo.bat) 查看效果,然后尝试修改resources/log4j2.xml里的日志级别,再次运行,观察变化 。

转载地址:http://fytwl.baihongyu.com/

你可能感兴趣的文章
(十四)Java springcloud B2B2C o2o多用户商城 springcloud架构- Spring Cloud构建分布式电子商务平台...
查看>>
Ansible 常用
查看>>
解决yum安装mysql时Requires: libc.so.6(GLIBC_2.17)(64bit)
查看>>
阿里云ECS云服务器规格如何选择?根据使用场景选择规格
查看>>
深入理解uwsgi和gunicorn网络模型
查看>>
Trapcode套装插件原创图文/视频安装教程
查看>>
flowable实现多实例节点的自由跳转
查看>>
算法偏见侦探
查看>>
信用体系,生态之魂!——保险科技生态建设
查看>>
彩铅,梦境
查看>>
java基础学习_GUI_如何让Netbeans的东西Eclipse能访问、GUI(图形用户接口)_day25总结...
查看>>
java多线程--信号量Semaphore的使用
查看>>
中国存储芯片进入战略关键期
查看>>
市场上的视觉图像采集卡软硬功能对比
查看>>
阿里专家与你分享:你必须了解的Java多线程技术
查看>>
张高兴的 Windows 10 IoT 开发笔记:三轴数字罗盘 HMC5883L
查看>>
rocketmq 同步双写
查看>>
细数国内无人机的江湖门派
查看>>
张高兴的 Windows 10 IoT 开发笔记:部署 ASP.NET Core 2 应用
查看>>
ARM 和 RISC-V 公然开撕,GNOME 之父指责 ARM
查看>>