Skip to content
Advertisement

Why are log4j classes loaded by two class loaders?

I have a maven project for an application, which I run in a WildFly server. The project has log4j dependencies:

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.1</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.1</version>
</dependency>

I would like to get the LoggerContext like this:

LoggerContext ctx = (LoggerContext) LogManager.getContext(false);

However, this results in ClassCastException:

class org.apache.logging.log4j.core.LoggerContext cannot be cast to class org.apache.logging.log4j.core.LoggerContext (org.apache.logging.log4j.core.LoggerContext is in unnamed module of loader 'deployment.WEB.war' @6e285ef6; org.apache.logging.log4j.core.LoggerContext is in unnamed module of loader 'deployment.WEB.war' @239cb91f)

After some debugging, I have discovered that the problem is that the class LoggerContext is loaded via two different classloaders. How could this be possible? At first, I thought that there would be two different declarations of these dependencies but that probably isn’t that problem. (I have changed the version to 2.17.0 and called class.getPackage().getSpecificationVersion() on both LoggerContext classes. For both classes the version has changed).

What could be the reason for the class being loaded twice?

Advertisement

Answer

Well, it seems that the classes were loaded twice because of the log4j libraries which are present in the Wildfly.

How to avoid this: Add a configuration to WEB-INF to exclude the logging libraries from the wildfly:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
<deployment>
    <exclude-subsystems>
        <subsystem name="logging"/>
    </exclude-subsystems>
    <exclusions>
        <module name="org.apache.commons.logging"/>
        <module name="org.apache.log4j"/>
        <module name="org.jboss.logging"/>
        <module name="org.jboss.logging.jul-to-slf4j-stub"/>
        <module name="org.jboss.logmanager"/>
        <module name="org.jboss.logmanager.log4j"/>
        <module name="org.slf4j"/>
        <module name="org.slf4j.impl"/>
    </exclusions>
</deployment>
</jboss-deployment-structure>
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement