简体   繁体   English

更改Java类加载器的优先级

[英]Changing the Priority of Java Classloaders

It's possible this has already been asked, but if so I've been unable to find it. 可能已经有人问过这个问题,但是如果是这样,我一直找不到。

The Ask 询问

Is there a way in Java 1.7/1.8, short of implementing a custom classloader, to make the application classpath higher-priority (loaded earlier) than the extension classpath? 在Java 1.7 / 1.8中,有没有一种方法可以实现自定义类加载器,而不是使应用程序类路径比扩展类路径具有更高的优先级(加载之前)?

The Issue 问题

We have a platform with multiple apps using Apache's log4j library. 我们有一个使用Apache的log4j库的具有多个应用程序的平台。 We also have a custom JCA security provider installed in [jre]/lib/ext which also uses log4j. 我们还在[jre] / lib / ext中安装了一个自定义JCA安全提供程序,该提供程序使用log4j。 In order to do so, log4j has to be installed along with the provider in the ext directory. 为此,必须在ext目录中将log4j与提供程序一起安装。

One of the apps on the platform (Apache's activemq) relies on an older version of log4j/slf4j than the provider's. 该平台上的一个应用程序(Apache的activemq)依赖于提供者的log4j / slf4j较旧的版本。 And since the provider's log4j jars are in [jre]/lib/ext, they override activemq's, causing a NoSuchMethodError to occur: 由于提供者的log4j jar位于[jre] / lib / ext中,因此它们会覆盖activemq的jar,从而导致发生NoSuchMethodError:

java.lang.NoSuchMethodError: org.slf4j.spi.LocationAwareLogger.log(Lorg/slf4j/Marker;Ljava/lang/String;ILjava/lang/String;Ljava/lang/Throwable;)V

So is there a way to make the jars in the application classpath supersede the extension directory? 那么有没有办法使应用程序类路径中的jar取代扩展目录?

Reproduction 再生产

You can reproduce this issue by installing these jars into [jre]/lib/ext: 您可以通过将以下jar安装到[jre] / lib / ext中来重现此问题:

  • log4j-1.2.17.jar log4j的-1.2.17.jar
  • slf4j-api-1.7.2.jar SLF4J-API-1.7.2.jar
  • slf4j-log4j12-1.7.2.jar SLF4J-log4j12-1.7.2.jar

And by installing these jars in the application classpath: 并通过在应用程序类路径中安装以下jar:

  • log4j-1.2.14.jar log4j的-1.2.14.jar
  • slf4j-api-1.5.11.jar SLF4J-API 1.5.11.jar
  • slf4j-log4j12-1.5.11.jar SLF4J-log4j12-1.5.11.jar

And by running this code: 并通过运行以下代码:

import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import org.slf4j.LoggerFactory;
import org.slf4j.spi.LocationAwareLogger;

public class LogApp {

    public final static LocationAwareLogger logger =
            (LocationAwareLogger) LoggerFactory.getLogger(LogApp.class);

    public static void main(String[] args) throws NoSuchAlgorithmException {
        // Make sure custom security provider has been initialized.
        SecureRandom rand = SecureRandom.getInstanceStrong();
        rand.doubles();

        //ClassLoader cl = ClassLoader.getSystemClassLoader();

        LogApp.logger.error("error: {}: {}", "string", new Exception());
        LogApp.logger.log(null, LogApp.class.getCanonicalName(),
                logger.ERROR_INT, "some message", new Exception());
    }

}

Which should generate this error: 哪个会产生此错误:

Exception in thread "main" java.lang.NoSuchMethodError: org.slf4j.spi.LocationAwareLogger.log(Lorg/slf4j/Marker;Ljava/lang/String;ILjava/lang/String;Ljava/lang/Throwable;)V
    at LogApp.main(LogApp.java:23)

Answer 回答

Run Java with this parameter: 使用以下参数运行Java:

-Xbootclasspath/p:[path_to_app_libs]/log4j-1.2.14.jar:[path_to_app_libs]/slf4j-api-1.5.11.jar:[path_to_app_libs]/slf4j-log4j12-1.5.11.jar

If you have control how your java is run, you can use -Xbootclasspath/a:path/to/your.jar to force loading specific jar ahead of extensions. 如果可以控制Java的运行方式,则可以使用-Xbootclasspath / a:path / to / your.jar强制在扩展程序之前加载特定的jar。

Upgrading log4j in lib/ext might be easier solution. 在lib / ext中升级log4j可能是更简单的解决方案。 Hopefully, whatever requires log4j in lib/ext will survive newer version, otherwise, you will have issues in any case, as bootclasspath will take precedence and force your lib/ext code to use new version. 希望,lib / ext中需要log4j的任何内容都可以在较新的版本中生存,否则,在任何情况下您都会遇到问题,因为bootclasspath将具有优先权,并强制您的lib / ext代码使用新版本。

In any case, having libraries with specific versions of log4j is bad pratice. 无论如何,拥有特定版本的log4j的库是不切实际的。 Anything but final application, should probably use slf4j without specific binding, or possibly JUL. 除了最终应用程序外,任何东西都应该使用没有特定绑定的slf4j,或者可能是JUL。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM