热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

gradle项目中资源文件的相对路径打包技巧必看

这篇文章主要介绍了gradle项目中资源文件的相对路径打包技巧必看篇,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

开发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)

public Configuration getConfiguration(final String name, final URI configLocation) {
   if (cOnfigLocation== null) {
    final String cOnfigLocationStr= this.substitutor.replace(PropertiesUtil.getProperties()
      .getStringProperty(CONFIGURATION_FILE_PROPERTY));
    if (configLocationStr != null) {
     ConfigurationSource source = null;
     try {
      source = getInputFromUri(NetUtils.toURI(configLocationStr));
     } catch (final Exception ex) {
      // Ignore the error and try as a String.
      LOGGER.catching(Level.DEBUG, ex);
     }
     if (source == null) {
      final ClassLoader loader = LoaderUtil.getThreadContextClassLoader();
      source = getInputFromString(configLocationStr, loader);
     }
     if (source != null) {
      for (final ConfigurationFactory factory : getFactories()) {
       final String[] types = factory.getSupportedTypes();
       if (types != null) {
        for (final String type : types) {
         if (type.equals("*") || configLocationStr.endsWith(type)) {
          final Configuration cOnfig= factory.getConfiguration(source);
          if (config != null) {
           return config;
          }
         }
        }
       }
      }
     }
    } else {
     for (final ConfigurationFactory factory : getFactories()) {
      final String[] types = factory.getSupportedTypes();
      if (types != null) {
       for (final String type : types) {
        if (type.equals("*")) {
         final Configuration cOnfig= factory.getConfiguration(name, configLocation);
         if (config != null) {
          return config;
         }
        }
       }
      }
     }
    }
   } else {
    // configLocation != null
    final String cOnfigLocationStr= configLocation.toString();
    for (final ConfigurationFactory factory : getFactories()) {
     final String[] types = factory.getSupportedTypes();
     if (types != null) {
      for (final String type : types) {
       if (type.equals("*") || configLocationStr.endsWith(type)) {
        final Configuration cOnfig= factory.getConfiguration(name, configLocation);
        if (config != null) {
         return config;
        }
       }
      }
     }
    }
   }
   Configuration cOnfig= getConfiguration(true, name);
   if (cOnfig== null) {
    cOnfig= getConfiguration(true, null);
    if (cOnfig== null) {
     cOnfig= getConfiguration(false, name);
     if (cOnfig== null) {
      cOnfig= getConfiguration(false, null);
     }
    }
   }
   if (config != null) {
    return config;
   }
   LOGGER.error("No log4j2 configuration file found. Using default configuration: logging only errors to the console.");
   return new DefaultConfiguration();
  }

其中常量CONFIGURATION_FILE_PROPERTY的定义为:

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

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

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

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

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

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import java.io.File;
public class ApplicationContextUtil {
 private static ConfigurableApplicationContext cOntext= null;
 private static ApplicationContextUtil instance = null;
 public static ApplicationContextUtil getInstance() {
  if (instance == null) {
   synchronized (ApplicationContextUtil.class) {
    if (instance == null) {
     instance = new ApplicationContextUtil();
    }
   }
  }
  return instance;
 }
 public ConfigurableApplicationContext getContext() {
  return context;
 }
 private ApplicationContextUtil() {
 }
 static {
  //加载log4j2.xml
  String cOnfigLocation= "resources/log4j2.xml";
  File cOnfigFile= new File(configLocation);
  if (!configFile.exists()) {
   System.err.println("log4j2 config file:" + configFile.getAbsolutePath() + " not exist");
   System.exit(0);
  }
  System.out.println("log4j2 config file:" + configFile.getAbsolutePath());
  try {
   //注:这一句必须放在整个应用第一次LoggerFactory.getLogger(XXX.class)前执行
   System.setProperty("log4j.configurationFile", configFile.getAbsolutePath());
  } catch (Exception e) {
   System.err.println("log4j2 initialize error:" + e.getLocalizedMessage());
   System.exit(0);
  }
  //加载spring配置文件
  cOnfigLocation= "resources/spring-context.xml";
  cOnfigFile= new File(configLocation);
  if (!configFile.exists()) {
   System.err.println("spring config file:" + configFile.getAbsolutePath() + " not exist");
   System.exit(0);
  }
  System.out.println("spring config file:" + configFile.getAbsolutePath());
  if (cOntext== null) {
   cOntext= new FileSystemXmlApplicationContext(configLocation);
   System.out.println("spring load success!");
  }
 }
}

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

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
/**
 * Created by yangjunming on 12/15/15.
 * author: yangjunming@huijiame.com
 */
public class App {
 private static ApplicationContext context;
 private static Logger logger;
 public static void main(String[] args) {
  cOntext= ApplicationContextUtil.getInstance().getContext();
  logger = LoggerFactory.getLogger(App.class);
  System.out.println("start ...");
  logger.debug("debug message");
  logger.info("info message");
  logger.warn("warn message");
  logger.error("error message");
  System.out.println(context.getBean(SampleObject.class));
 }
}

再次友情提醒: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目录下了,参考下图:

最后国际惯例,给个示例源码:https://github.com/yjmyzz/config-load-demo

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

以上这篇gradle项目中资源文件的相对路径打包技巧必看就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。


推荐阅读
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • Skywalking系列博客1安装单机版 Skywalking的快速安装方法
    本文介绍了如何快速安装单机版的Skywalking,包括下载、环境需求和端口检查等步骤。同时提供了百度盘下载地址和查询端口是否被占用的命令。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • EPICS Archiver Appliance存储waveform记录的尝试及资源需求分析
    本文介绍了EPICS Archiver Appliance存储waveform记录的尝试过程,并分析了其所需的资源容量。通过解决错误提示和调整内存大小,成功存储了波形数据。然后,讨论了储存环逐束团信号的意义,以及通过记录多圈的束团信号进行参数分析的可能性。波形数据的存储需求巨大,每天需要近250G,一年需要90T。然而,储存环逐束团信号具有重要意义,可以揭示出每个束团的纵向振荡频率和模式。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • Windows下配置PHP5.6的方法及注意事项
    本文介绍了在Windows系统下配置PHP5.6的步骤及注意事项,包括下载PHP5.6、解压并配置IIS、添加模块映射、测试等。同时提供了一些常见问题的解决方法,如下载缺失的msvcr110.dll文件等。通过本文的指导,读者可以轻松地在Windows系统下配置PHP5.6,并解决一些常见的配置问题。 ... [详细]
  • 本文介绍了在Win10上安装WinPythonHadoop的详细步骤,包括安装Python环境、安装JDK8、安装pyspark、安装Hadoop和Spark、设置环境变量、下载winutils.exe等。同时提醒注意Hadoop版本与pyspark版本的一致性,并建议重启电脑以确保安装成功。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 【MicroServices】【Arduino】装修甲醛检测,ArduinoDart甲醛、PM2.5、温湿度、光照传感器等,数据记录于SD卡,Python数据显示,UI5前台,微服务后台……
    这篇文章介绍了一个基于Arduino的装修甲醛检测项目,使用了ArduinoDart甲醛、PM2.5、温湿度、光照传感器等硬件,并将数据记录于SD卡,使用Python进行数据显示,使用UI5进行前台设计,使用微服务进行后台开发。该项目还在不断更新中,有兴趣的可以关注作者的博客和GitHub。 ... [详细]
  • 本文介绍了关于apache、phpmyadmin、mysql、php、emacs、path等知识点,以及如何搭建php环境。文章提供了详细的安装步骤和所需软件列表,希望能帮助读者解决与LAMP相关的技术问题。 ... [详细]
  • imx6ull开发板驱动MT7601U无线网卡的方法和步骤详解
    本文详细介绍了在imx6ull开发板上驱动MT7601U无线网卡的方法和步骤。首先介绍了开发环境和硬件平台,然后说明了MT7601U驱动已经集成在linux内核的linux-4.x.x/drivers/net/wireless/mediatek/mt7601u文件中。接着介绍了移植mt7601u驱动的过程,包括编译内核和配置设备驱动。最后,列举了关键词和相关信息供读者参考。 ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • 标题: ... [详细]
author-avatar
Ailsa大宝贝
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有