战争应用程序中的Java类加载器(jar / classloader hell)quartz

时间:2013-02-16 00:43:45

标签: java tomcat classloader quartz-scheduler

我有一个maven项目设置,例如

parent
...pom.xml
...servlet-app 
......pom.xml ( specifies simple-lib as a dependency )
...simple-lib
......src/main/resources/config.properties
......src/main/java/package1/Config.java
......src/main/java/package1/HelloQuartzJob.java

基本上servlet应用程序servlet-app将simple-lib指定为依赖项。配置文件config.properties打包在simple-lib.jar的顶层/级别。当我解压缩servelet-app.war时,我可以看到WEB_INF / lib / simple-lib.jar。所以,一切都很好。

Config.java看起来像这样:

public class Config{

    static final String PROPERTILES_FILE = "config.properties";
    static Properties props;
    static{
        log.info("Loading Config properties from {}", PROPERTILES_FILE);
        props = new Properties();

        try {
            InputStream is = ClassLoader.getSystemResourceAsStream(PROPERTILES_FILE);
            if (is == null) {
                log.info("Loading through ClassLoader as root");
                is = ClassLoader.getSystemResourceAsStream("/"+PROPERTILES_FILE);
            }
            if (is == null) {
                log.info("Loading through Config.class. root");
                is = Config.class.getResourceAsStream("/"+PROPERTILES_FILE);
            }
            if (is == null) {
                log.info("Loading through Config.class. relative");
                is = Config.class.getResourceAsStream(PROPERTILES_FILE);
            }
            if( is == null ) {
                log.info("Thread class loader root");
                is = Thread.currentThread().getContextClassLoader().getResourceAsStream("/"+PROPERTILES_FILE);
            }
            props.load(is);
        } catch (Throwable e) {
            log.error("Config properties loading error ", e);
            throw new RuntimeException(e);
        }
    }
}

但是,当我在tomcat7中部署它时,我得到一个NoClassDefFound /无法初始化package1.Config错误。我相信这是因为classLoaders。

同样令人感兴趣的是,这个package1.Config由HelloQuartzJob.java使用,它是一个石英作业,由在这个servlet应用程序中运行的调度程序实例运行。

任何指针?

3 个答案:

答案 0 :(得分:0)

你应该替换这一行:

InputStream is = ClassLoader.getSystemResourceAsStream(PROPERTILES_FILE);

使用:

InputStream is = Config.class.getClassLoader().getResourceAsStream(PROPERTILES_FILE);

为了使用当前的webapp类加载器及其根源于战争根源。

答案 1 :(得分:0)

我看到两个问题:

is = ClassLoader.getSystemResourceAsStream("/"+PROPERTILES_FILE);

is = Thread.currentThread().getContextClassLoader().getResourceAsStream("/"+PROPERTILES_FILE);

直接从类加载器加载资源时,不要使用前导'/'字符。

Class.getResourceAsStream()使用前导'/'(因为资源是相对于类的包加载的),但对于ClassLoader.getResourceAsStream()getSystemResourceAsStream()不是使用前导'/'。

答案 2 :(得分:0)

您需要从类加载器实例中请求资源。

来自静态背景:

String url = Config.class.getClassLoader().getResource("config.properties");
InputStream is = Config.class.getClassLoader().getResourceAsStream("config.properties");

来自一个实例:

String url = getClass().getClassLoader().getResource("config.properties");
InputStream is = getClass().getClassLoader().getResourceAsStream("config.properties");

您应该只使用相对路径而不是绝对路径(以" /"开头)来访问webapp上下文中的jar资源。

昨天我遇到了同样的麻烦,这样很容易解决: - )

这只是一个simle classLoader问题,但它非常重要。如果使用绝对路径,则加载程序只会查看WEB-INF / classes文件夹。