6

我的一个项目被打包为一个 EAR 文件,其中包含 SLF4J API (1.7.5) 以及作为其实现的 logback 库 (logback-core 1.0.13logback-classic 1.0.13)。

当我(曾经)部署我的项目时,SLF4J 的 LoggerFactory 发现 logback 作为可能的绑定并使用了正确的记录器(即 logback)。

现在我有一个资源连接器 ( activemq-rar-5.8.0.rar),它部署在我自己的 EAR 文件之前(因为 EAR 文件需要 RAR)。不幸的是,这个 RAR 包含它自己的 SLF4J 实现(slf4j-api-1.6.6.jar slf4j-log4j12-1.6.6.jar log4j-1.2.17.jar)。RAR 文件使用 log4j 实现。

当我部署我的 EAR 文件时,我的应用程序代码中的 LoggerFactory 突然使用 log4j 实现 ( org.slf4j.impl.Log4jLoggerAdapter) - 即使我希望类路径与 RAR 分开。

情况似乎并非如此 - 那么我做错了什么(RAR 应该使用 log4j,我的 EAR 应该使用 logback)?


更新 1: 看起来我并不孤单,但不幸的是缺少答案..


更新 2:

根据表,GlassFish 在 EAR/WAR 库(这是最后加载的库)之前加载连接器模块。


更新 3:

我设法修复了“绑定”:如果我将slf4j-api-1.7.5.jar和 logback 实现(logback-core-1.0.13.jarlogback-classic-1.0.13.jar)放在domains/<myDomain>/libGlassFish 中的文件夹中,logback 将用作日志记录实现(请参阅更新 2 - “Common Classloader”位于“Connector Classloader”之前)。

不幸的是,我的配置文件已经找不到了,因为它们在 WAR/EAR 中——稍后将由不同的类加载器(“归档类加载器”)加载。

所以这对我来说并不是一个真正的解决方案,因为我想将 logback 配置文件保留在 EAR/WAR 中(因为每个应用程序都使用不同的配置)。


亲切的问候

愚蠢的羊

4

1 回答 1

1

我终于想出了一个可以接受的解决方案。

GlassFish 在 EAR/WAR 之前加载连接器模块,请参阅“更新 2”。通过在加载连接器模块之前提供 SLF4J 实现,使用我提供的 SLF4J 实现。

为此,我已将以下 JARS 复制到目录中domains/<myDomain>/lib(请参阅“更新 3”)。

  • logback-core-1.0.13.jar
  • logback-classic-1.0.13.jar
  • slf4j-api-1.7.5.jar

logback.xml不幸的是, logback没有找到它自己的配置文件(

解决办法是手动配置logback。我已经使用以下 CDI 生产者完成了这项工作:

package com.example;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;

@ApplicationScoped
public class LoggerProducer {
    @PostConstruct
    public void initialize() {
        // The following is logback specific. Unfortunately logback doesn't find its XML configuration
        // as the logback implementation gets loaded by a different ClassLoader than this code.
        // See http://docs.oracle.com/cd/E19226-01/820-7695/6niugesfp/index.html#indexterm-28
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
        JoranConfigurator joranConfigurator = new JoranConfigurator();
        joranConfigurator.setContext(lc);
        lc.reset();

        try {
            // The logback configuration is now being loaded from the classpath (by the "Archive Classloader")
            joranConfigurator.doConfigure(this.getClass().getClassLoader().getResource("logback.xml"));
        } catch (JoranException e) {
            e.printStackTrace();
        }
    }

    @Produces
    @ApplicationLogger
    Logger createLogger(InjectionPoint injectionPoint) {
        return LoggerFactory.getLogger(injectionPoint.getMember().getDeclaringClass());
    }
}

这将配置 logback。请注意,我使用 logback 特定代码来执行此操作,因此如果您更改 SLF4J 实现,您也必须更改LoggerProducer

我认为 logback 找不到它的配置文件,因为“通用类加载器”在其类路径上没有 EAR/WAR。但是稍后,当应用程序被加载时,“存档类加载器”logback.xml在其类路径中具有 (因为它由 EAR/WAR 文件提供),因此一旦一切就绪,就可以配置 logback。

问候愚蠢的羊

于 2013-08-13T13:00:57.537 回答