SLF4J - 绑定被同一应用程序服务器上的其他应用程序覆盖

stu*_*eep 6 java activemq-classic glassfish classpath slf4j

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

当我(以前)部署我的项目时,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将用作日志记录实现(请参阅Update 2 - "Common Classloader"在"Connector Classloader"之前).

不幸的是我的配置文件不再存在,因为它们在WAR/EAR中 - 稍后将由不同的类加载器("Archive Classloader")加载.

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


亲切的问候

stupidSheep

stu*_*eep 1

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

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

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

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

不幸的是,logback 不再找到它自己的配置文件 ( logback.xml),它必须位于类路径上(确实如此,因为我将它打包在 JAR 中)。

解决办法是手动配置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());
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

问候愚蠢的羊