ClassCircularityError没有明显的原因(阻止递归类加载)

时间:2015-10-21 02:12:45

标签: java classloader

几天前发生了有趣的问题。我们找到了解决方法,但原因尚不清楚。

我们有内部分布式日志跟踪器,它允许我们从分布式系统实时收集日志。 Tracer实现为logback扩展。在部署新版本时,我们抓住了ClassCircularityError

java.lang.ClassCircularityError: ch/qos/logback/core/spi/FilterReply
    at me.bazhenov.whisperer.ActivatingTurboFilter.decide(ActivatingTurboFilter.java:33)
    at ch.qos.logback.classic.spi.TurboFilterList.getTurboFilterChainDecision(TurboFilterList.java:62)
    at ch.qos.logback.classic.LoggerContext.getTurboFilterChainDecision_0_3OrMore(LoggerContext.java:252)

这很有意思,因为FilterReply是枚举,除了java.util.Enum之外没有任何父母。所以,我认为ClassCircularityError没有任何可能性。

在尝试调试此错误时,我们在开发环境中使用不同版本的Jetty运行Web应用程序。令人惊讶的是,得到了(注意行标记为*):

Exception in thread "Scanner-0" java.lang.StackOverflowError
    at java.io.UnixFileSystem.getBooleanAttributes0(Native Method)
    at java.io.UnixFileSystem.getBooleanAttributes(UnixFileSystem.java:242)
    at java.io.File.exists(File.java:819)
    at sun.misc.URLClassPath$FileLoader.getResource(URLClassPath.java:1245)
    at sun.misc.URLClassPath.getResource(URLClassPath.java:212)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:365)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
    at org.eclipse.jetty.webapp.WebAppClassLoader.findClass(WebAppClassLoader.java:524)
    at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:457)
    at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:417)
*   at me.bazhenov.whisperer.ActivatingTurboFilter.decide(ActivatingTurboFilter.java:32)
    at ch.qos.logback.classic.spi.TurboFilterList.getTurboFilterChainDecision(TurboFilterList.java:62)
    at ch.qos.logback.classic.LoggerContext.getTurboFilterChainDecision_0_3OrMore(LoggerContext.java:252)
    at ch.qos.logback.classic.Logger.callTurboFilters(Logger.java:772)
    at ch.qos.logback.classic.Logger.isDebugEnabled(Logger.java:490)
    at ch.qos.logback.classic.Logger.isDebugEnabled(Logger.java:486)
    at org.eclipse.jetty.util.log.JettyAwareLogger.isDebugEnabled(JettyAwareLogger.java:170)
    at org.eclipse.jetty.util.log.Slf4jLog.isDebugEnabled(Slf4jLog.java:110)
    at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:474)
    at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:417)
*   at me.bazhenov.whisperer.ActivatingTurboFilter.decide(ActivatingTurboFilter.java:32)
    at ch.qos.logback.classic.spi.TurboFilterList.getTurboFilterChainDecision(TurboFilterList.java:62)
    at ch.qos.logback.classic.LoggerContext.getTurboFilterChainDecision_0_3OrMore(LoggerContext.java:252)
    at ch.qos.logback.classic.Logger.callTurboFilters(Logger.java:772)
    at ch.qos.logback.classic.Logger.isDebugEnabled(Logger.java:490)
    at ch.qos.logback.classic.Logger.isDebugEnabled(Logger.java:486)
    at org.eclipse.jetty.util.log.JettyAwareLogger.isDebugEnabled(JettyAwareLogger.java:170)
    at org.eclipse.jetty.util.log.Slf4jLog.isDebugEnabled(Slf4jLog.java:110)
    at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:474)
    at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:417)
*   at me.bazhenov.whisperer.ActivatingTurboFilter.decide(ActivatingTurboFilter.java:32)
    at ch.qos.logback.classic.spi.TurboFilterList.getTurboFilterChainDecision(TurboFilterList.java:62)
    at ch.qos.logback.classic.LoggerContext.getTurboFilterChainDecision_0_3OrMore(LoggerContext.java:252)
    at ch.qos.logback.classic.Logger.callTurboFilters(Logger.java:772)
    at ch.qos.logback.classic.Logger.isDebugEnabled(Logger.java:490)
    at ch.qos.logback.classic.Logger.isDebugEnabled(Logger.java:486)
    [...]
    at org.eclipse.jetty.util.log.JettyAwareLogger.isDebugEnabled(JettyAwareLogger.java:170)
    at org.eclipse.jetty.util.log.Slf4jLog.isDebugEnabled(Slf4jLog.java:110)
    at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:474)
    at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:417)

ActivatingTurboFilter.java:32包含以下代码:

String value = MDC.get(key)

这似乎是递归类加载问题。其中一个类加载器进行日志记录,因此控制流程会在ActivatingTurboFilter中返回,因为我们使用自定义过滤器和附加程序扩展了Logback。但是仍然没有加载所需的类,所以循环关闭。

我们可以通过在ActivatingTurboFilter中添加静态初始值设定项来解决此问题:

static {
  MDC.get("foo")
}

这有效地加载了加载ActivatingTurboFilter本身的所有必需类,而不是调用ActivatingTurboFilter方法的时刻。

但问题仍然存在。 Java是否允许这种类型的“递归类加载”,如果是这样,为什么这个问题已经表现出来?

0 个答案:

没有答案