arn*_*olt 2 java cross-platform classloader
我有一个使用 Jetty 部署的 Java Web 应用程序(使用 Spring)。如果我尝试在 Windows 机器上运行它,一切都按预期工作,但是如果我尝试在我的 Linux 机器上运行相同的代码,它会像这样失败:
【正常启动输出】 11:16:39.657 INFO [main] org.mortbay.jetty.servlet.ServletHandler$Context.log>(ServletHandler.java:1145)>16> 设置 Web 应用程序根系统属性:'webapp.root' = [/path/到/工作/目录] java.lang.reflect.InvocationTargetException 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 在 java.lang.reflect.Method.invoke(Method.java:597) 在 org.mortbay.start.Main.invokeMain(Main.java:151) 在 org.mortbay.start.Main.start(Main.java:476) 在 org.mortbay.start.Main.main(Main.java:94) 引起:java.lang.ExceptionInInitializerError 在 org.springframework.web.util.Log4jWebConfigurer.initLogging(Log4jWebConfigurer.java:129) 在 org.springframework.web.util.Log4jConfigListener.contextInitialized(Log4jConfigListener.java:51) 在 org.mortbay.jetty.servlet.WebApplicationContext.doStart(WebApplicationContext.java:495) 在 org.mortbay.util.Container.start(Container.java:72) 在 org.mortbay.http.HttpServer.doStart(HttpServer.java:708) 在 org.mortbay.util.Container.start(Container.java:72) 在 org.mortbay.jetty.Server.main(Server.java:460) ……还有 7 个 引起:org.apache.commons.logging.LogConfigurationException: org.apache.commons.logging.LogConfigurationException: 没有合适的日志构造函数 [Ljava.lang.Class;@15311bd for org.apache.commons.logging.impl.Log4JLogger (Caused通过 java.lang.NoClassDefFoundError: org/apache/log4j/Category) (由 org.apache.commons.logging.LogConfigurationException 引起:没有合适的日志构造函数 [Ljava.lang.Class;@15311bd for org.apache.commons.logging。 impl.Log4JLogger(由 java.lang.NoClassDefFoundError 引起:org/apache/log4j/Category)) 在 org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImpl.java:543) 在 org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:235) 在 org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:209) 在 org.apache.commons.logging.LogFactory.getLog(LogFactory.java:351) 在 org.springframework.util.SystemPropertyUtils.(SystemPropertyUtils.java:42) ……还有 14 个 引起:org.apache.commons.logging.LogConfigurationException:没有合适的日志构造函数[Ljava.lang.Class;@15311bd for org.apache.commons.logging.impl.Log4JLogger(由java.lang.NoClassDefFoundError引起:org/apache /log4j/类别) 在 org.apache.commons.logging.impl.LogFactoryImpl.getLogConstructor(LogFactoryImpl.java:413) 在 org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImpl.java:529) ……还有 18 个 引起:java.lang.NoClassDefFoundError:org/apache/log4j/Category 在 java.lang.Class.getDeclaredConstructors0(Native Method) 在 java.lang.Class.privateGetDeclaredConstructors(Class.java:2389) 在 java.lang.Class.getConstructor0(Class.java:2699) 在 java.lang.Class.getConstructor(Class.java:1657) 在 org.apache.commons.logging.impl.LogFactoryImpl.getLogConstructor(LogFactoryImpl.java:410) ... 19 更多 引起:java.lang.ClassNotFoundException:org.apache.log4j.Category 在 java.net.URLClassLoader$1.run(URLClassLoader.java:200) 在 java.security.AccessController.doPrivileged(Native Method) 在 java.net.URLClassLoader.findClass(URLClassLoader.java:188) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:307) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:252) 在 java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320) ……还有 24 个 【关机输出】
我已经使用 运行了应用程序java -verbose:class
,并且根据该输出,org.apache.log4j.Category 从我的 /WEB-INF/lib 中的 log4j JAR 加载,就在抛出第一个异常之前。
现在,两台机器上的 Java 版本略有不同。两台机器都是 Sun 的 java,Linux 机器是 1.6.0_10,而 Windows 机器是 1.6.0_08,或者可能是 07 或 06,我现在不记得确切的数字,手头也没有机器. 但是即使 Java 的次要版本略有不同,代码也不应该像这样中断。有谁明白这里有什么问题?
你必须明白,类加载器不能看到一切;他们只能看到父类加载器加载了什么或他们自己加载了什么。因此,如果您有两个类加载器,一个用于 Jetty,另一个用于您的 webapp,您的 webapp 可以看到 log4j(因为 JAR 是 WEB-INF/lib)但 Jetty 的类加载器不能。
如果您设法使使用 log4j 但最终在 Jetty 的上下文(和类加载器)中运行的类可用于 Jetty(例如 DB 层中的某些内容),您将收到错误消息。
要调试它,请在 org.springframework.web.util.Log4jWebConfigurer.initLogging() 中设置一个断点。如果可以,将此类的源代码复制到您的项目中(之后不要忘记将其删除)并添加以下行:
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Run Code Online (Sandbox Code Playgroud)
查看调试器中的 cl 对象。这应该会给你一些创建它的信息。我的猜测是这是来自 Jetty 的类加载器。
[编辑] 请注意,如果您在两个类加载器中都有 log4j,您会遇到不同的麻烦:在这种情况下,您将有两个同名的类,它们创建的对象与赋值不兼容!所以请确保这个 jar 只有一个实例,或者 log4j 的实例永远不会在两个上下文之间传递(这通常是不可能的)。
归档时间: |
|
查看次数: |
4986 次 |
最近记录: |