无法在 Spring 引导 Web 应用程序中覆盖 java.util.logging.LogManager:在已加载的 class 上获取 java.lang.ClassNotFoundException
Can't override java.util.logging.LogManager in a Spring Boot web application: Getting java.lang.ClassNotFoundException on already loaded class
我正在尝试用我自己的配置覆盖 java.util.logging.LogManager
:
class CloudwatchHandler 是 Handler
的一个实现,包括这个 init()
方法:
public static void init() {
final String julConfigFile = System.getProperty("java.util.logging.config.file");
if(julConfigFile != null) {
try (InputStream is = new FileInputStream(julConfigFile)) {
LogManager logManager = LogManager.getLogManager();
logManager.reset();
logManager.readConfiguration(is);
Logger logger = Logger.getLogger(CloudwatchHandler.class.getName());
logger.info("LOADED");
} catch (SecurityException | IOException e) {
System.err.println(Instant.now() + ": Failed to initialize JUL.");
e.printStackTrace(System.err);
throw new RuntimeException(e);
}
}
else {
System.err.println(Instant.now() + ": java.util.logging.config.file was not specified");
}
}
主应用程序class
public static void main(String[] args) {
CloudwatchHandler.init();
SpringApplication.run(MyApp.class, args);
}
错误
Can't load log handler "mypackage.CloudwatchHandler"
java.lang.ClassNotFoundException: mypackage.CloudwatchHandler
java.lang.ClassNotFoundException: mypackage.CloudwatchHandler
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
at java.logging/java.util.logging.LogManager.createLoggerHandlers(LogManager.java:1005)
at java.logging/java.util.logging.LogManager.run(LogManager.java:975)
at java.logging/java.util.logging.LogManager.run(LogManager.java:971)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:318)
at java.logging/java.util.logging.LogManager.loadLoggerHandlers(LogManager.java:971)
at java.logging/java.util.logging.LogManager.initializeGlobalHandlers(LogManager.java:2424)
at java.logging/java.util.logging.LogManager$RootLogger.accessCheckedHandlers(LogManager.java:2526)
at java.logging/java.util.logging.Logger.getHandlers(Logger.java:2090)
at java.logging/java.util.logging.Logger.log(Logger.java:977)
at java.logging/java.util.logging.Logger.doLog(Logger.java:1007)
at java.logging/java.util.logging.Logger.log(Logger.java:1030)
at java.logging/java.util.logging.Logger.info(Logger.java:1803)
at mypackage.CloudwatchHandler.init(CloudwatchHandler.java:51)
... main ...
关于此异常的真正疯狂之处在于导致 ClassNotFoundException
的 class 实际上是当前堆栈帧中的调用者,如堆栈跟踪中所示。很明显它已被找到或不可能 运行.
这是什么原因造成的,我该如何解决?我只想加载我自己的日志处理程序。
Spring开机版本为2.6.3.
如果未部署处理程序以在 system class loader 中加载,则会发生 ClassNotFoundException,因为这是 LogManager 用于查找处理程序的内容。
更新您的测试用例并重试:
public static void main(String[] args) throws Exception {
System.out.println(ClassLoader.getSystemClassLoader());
System.out.println(Thread.currentThread().getContextClassLoader());
System.out.println(CloudwatchHandler.class.getClassLoader());
//This is what CloudwatchHandler.init(); triggers
Class.forName(CloudwatchHandler.class.getName(), true, Thread.currentThread().getContextClassLoader());
//This is what the LogManager is doing
Class.forName(CloudwatchHandler.class.getName(), true, ClassLoader.getSystemClassLoader());
//Force load the root handlers.
Logger.getLogger("").getHandlers();
CloudwatchHandler.init();
SpringApplication.run(MyApp.class, args);
}
如果处理程序部署在上下文 class 加载程序中而不是系统 classloader 中,那么您需要更改打包处理程序的方式,以便它对系统可见class装载机。 java.util.logging.config.class
选项是 LogManager 的一部分,它将尝试通过上下文 classloader 加载 classes,这将能够看到您的 classes。对于此选项,您将 init 方法的内容移动到一个新的 class 并让构造函数执行该操作。然后在命令行上将值设置为新配置的 FQCN class.
我正在尝试用我自己的配置覆盖 java.util.logging.LogManager
:
class CloudwatchHandler 是 Handler
的一个实现,包括这个 init()
方法:
public static void init() {
final String julConfigFile = System.getProperty("java.util.logging.config.file");
if(julConfigFile != null) {
try (InputStream is = new FileInputStream(julConfigFile)) {
LogManager logManager = LogManager.getLogManager();
logManager.reset();
logManager.readConfiguration(is);
Logger logger = Logger.getLogger(CloudwatchHandler.class.getName());
logger.info("LOADED");
} catch (SecurityException | IOException e) {
System.err.println(Instant.now() + ": Failed to initialize JUL.");
e.printStackTrace(System.err);
throw new RuntimeException(e);
}
}
else {
System.err.println(Instant.now() + ": java.util.logging.config.file was not specified");
}
}
主应用程序class
public static void main(String[] args) {
CloudwatchHandler.init();
SpringApplication.run(MyApp.class, args);
}
错误
Can't load log handler "mypackage.CloudwatchHandler"
java.lang.ClassNotFoundException: mypackage.CloudwatchHandler
java.lang.ClassNotFoundException: mypackage.CloudwatchHandler
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
at java.logging/java.util.logging.LogManager.createLoggerHandlers(LogManager.java:1005)
at java.logging/java.util.logging.LogManager.run(LogManager.java:975)
at java.logging/java.util.logging.LogManager.run(LogManager.java:971)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:318)
at java.logging/java.util.logging.LogManager.loadLoggerHandlers(LogManager.java:971)
at java.logging/java.util.logging.LogManager.initializeGlobalHandlers(LogManager.java:2424)
at java.logging/java.util.logging.LogManager$RootLogger.accessCheckedHandlers(LogManager.java:2526)
at java.logging/java.util.logging.Logger.getHandlers(Logger.java:2090)
at java.logging/java.util.logging.Logger.log(Logger.java:977)
at java.logging/java.util.logging.Logger.doLog(Logger.java:1007)
at java.logging/java.util.logging.Logger.log(Logger.java:1030)
at java.logging/java.util.logging.Logger.info(Logger.java:1803)
at mypackage.CloudwatchHandler.init(CloudwatchHandler.java:51)
... main ...
关于此异常的真正疯狂之处在于导致 ClassNotFoundException
的 class 实际上是当前堆栈帧中的调用者,如堆栈跟踪中所示。很明显它已被找到或不可能 运行.
这是什么原因造成的,我该如何解决?我只想加载我自己的日志处理程序。
Spring开机版本为2.6.3.
如果未部署处理程序以在 system class loader 中加载,则会发生 ClassNotFoundException,因为这是 LogManager 用于查找处理程序的内容。
更新您的测试用例并重试:
public static void main(String[] args) throws Exception {
System.out.println(ClassLoader.getSystemClassLoader());
System.out.println(Thread.currentThread().getContextClassLoader());
System.out.println(CloudwatchHandler.class.getClassLoader());
//This is what CloudwatchHandler.init(); triggers
Class.forName(CloudwatchHandler.class.getName(), true, Thread.currentThread().getContextClassLoader());
//This is what the LogManager is doing
Class.forName(CloudwatchHandler.class.getName(), true, ClassLoader.getSystemClassLoader());
//Force load the root handlers.
Logger.getLogger("").getHandlers();
CloudwatchHandler.init();
SpringApplication.run(MyApp.class, args);
}
如果处理程序部署在上下文 class 加载程序中而不是系统 classloader 中,那么您需要更改打包处理程序的方式,以便它对系统可见class装载机。 java.util.logging.config.class
选项是 LogManager 的一部分,它将尝试通过上下文 classloader 加载 classes,这将能够看到您的 classes。对于此选项,您将 init 方法的内容移动到一个新的 class 并让构造函数执行该操作。然后在命令行上将值设置为新配置的 FQCN class.