【问题标题】:Code running under ant doesn't find a properties file unless I fork the JVM除非我 fork JVM,否则在 ant 下运行的代码找不到属性文件
【发布时间】:2011-08-21 19:39:07
【问题描述】:

我刚刚开始使用 Ant,但在让“运行”目标工作时遇到了问题。我的部分代码加载了一个属性文件,除非我让我的运行目标使用新的 JVM,否则它总是找不到这个文件。下面是一个非常简化的示例,“run”目标失败,“run_fork”目标有效。我的理解是 Ant 有它自己的类加载器来替换默认的类加载器,所以我想这在某种程度上与搜索路径混淆了。有什么方法可以更改我的代码以使其工作而无需分叉一个新的 JVM?

build.xml:

<project name="PropsExample" default="compile" basedir=".">

<property name="src" location="src"/>
<property name="bin" location="bin"/>

<target name="init">
    <tstamp/>
    <mkdir dir="${bin}"/>
</target>

<target name="compile" depends="init">
    <javac includeAntRuntime="false" srcdir="${src}" destdir="${bin}"/>
    <copy todir="${bin}">
        <fileset dir="${src}" includes="**/*.properties"/>
    </copy>
</target>

<target name="clean">
    <delete dir="${bin}"/>
    <delete dir="${dist}"/>
</target>

<target name="run" depends="compile">
    <java classname="com.example.Test">
        <classpath>
            <pathelement location="${bin}"/>
        </classpath>
    </java>
</target>

<target name="run_fork" depends="compile">
    <java fork="true" classname="com.example.Test">
        <classpath>
            <pathelement location="${bin}"/>
        </classpath>
    </java>
</target>

示例代码:

package com.example;

import java.util.Properties;
import java.io.InputStream;

public class PropertiesLoader {

    public static String getProperty() throws Exception {

        InputStream in = ClassLoader.getSystemResourceAsStream("com/example/test.properties");
        if ( in == null ) {
            throw new Exception("Cannot find test.properties");
        }
        Properties p = new Properties();
        p.load(in);
        in.close();
        return p.getProperty("test");
    }
}

和:

package com.example;

public class Test {

    public static void main(String[] args) throws Exception {

        try {
            System.out.println(PropertiesLoader.getProperty());
        } catch ( Exception e ) {
            e.printStackTrace(System.out);
        }
    }
}

【问题讨论】:

  • 应该补充一下,这是Java 1.6.0_22和Ant 1.8.1

标签: java ant properties-file


【解决方案1】:

ANT 在读取包含您运行的指定类路径的 XML 文件时已经启动,实际上无法重置正在运行的 JVM 的类路径。相反,它会尝试在类加载器链中附加它;但是,您对类加载器的调用可能会获取根类加载器。你可能想做这样的事情:

this.getClass().getClassLoader().getResourceAsStream("com/example/test.properties");

这将强制类使用与加载相同的类加载器。这应该(希望)在正确的位置跳转到 ClassLoader 链,就好像它加载了当前类并且属性文件与当前类一起适当地“移动”,那么属性文件应该可以通过相同的类加载器访问。

请注意,无论如何都有很多好的理由来分叉 JVM。在我看来,最重要的是摆脱整个 JVM 的 ANT 相关类。您不想意外地将您的运行时绑定到仅在软件构建过程中可用的类,并且如果您想将您的类绑定到 ANT,则应将其作为第 3 方库进行管理(这样您就可以控制版本它与绑定程度、在 ANT 的多个版本/发行版中以相同方式重现构建的能力等相关)

【讨论】:

  • 抱歉,删除了多余的不必要的“类”。
  • 你的意思是getResourceAsStream 而不是getSystemResourceAsStream?
  • @Edwin 谢谢,正是出于这些原因,我倾向于总是分叉,似乎我正在做的事情应该有效。我发现无论我是否分叉都有效的另一行是Thread.currentThread().getContextClassLoader().getResourceAsStream("com/example/test.properties");,但我不完全理解为什么这行得通,因为没有线程正在进行(或者有线程吗?)。
  • @Abayliss,当 JVM 启动时,它会读取 CLASSPATH 属性变量并配置主类加载器(其中有 3 个)。然后它为 ANT 加载类,并开始处理 ANT 的代码,然后读取 build.xml 文件。在 build.xml 文件中,ANT 确定它需要通过 java 命令运行某些东西,因此它加载了所需的类。可是等等!该类不在类路径中,因此 ANT 使用它自己的类加载器(它可以根据命令创建/销毁)来加载该类。询问系统类加载器不会为 ant 配置的路径使用“正确”的类加载器。
  • @Abayliss,所以,告诉对象使用加载它的同一个类加载器来加载属性文件是加载属性文件的正确方法。如果您以不同的方式加载(例如在 ant 或 tomcat 或 EJB 容器中等),您无法确定系统类加载器是否了解加载的类(或其关联的属性文件)。它在 fork 100% 上工作的原因是因为 ANT 在启动时告诉分叉的 JVM,所以系统类加载器配置了 bin 路径。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-19
  • 2021-06-29
  • 2016-02-04
  • 1970-01-01
相关资源
最近更新 更多