لماذا جافا classloading تفشل على لينكس ولكن تنجح على ويندوز ؟

StackOverflow https://stackoverflow.com/questions/519816

سؤال

لدي جافا ويب التطبيق (باستخدام الربيع) ، نشر مع رصيف.إذا حاولت تشغيله على جهاز ويندوز كل شيء يعمل كما هو متوقع ، ولكن إذا حاولت تشغيل نفس القانون على آلة لينكس فشل مثل هذا:

[normal startup output]
11:16:39.657 INFO   [main] org.mortbay.jetty.servlet.ServletHandler$Context.log>(ServletHandler.java:1145) >16> Set web app root system property: 'webapp.root' = [/path/to/working/dir]
java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.mortbay.start.Main.invokeMain(Main.java:151)
        at org.mortbay.start.Main.start(Main.java:476)
        at org.mortbay.start.Main.main(Main.java:94)
Caused by: java.lang.ExceptionInInitializerError
        at org.springframework.web.util.Log4jWebConfigurer.initLogging(Log4jWebConfigurer.java:129)
        at org.springframework.web.util.Log4jConfigListener.contextInitialized(Log4jConfigListener.java:51)
        at org.mortbay.jetty.servlet.WebApplicationContext.doStart(WebApplicationContext.java:495)
        at org.mortbay.util.Container.start(Container.java:72)
        at org.mortbay.http.HttpServer.doStart(HttpServer.java:708)
        at org.mortbay.util.Container.start(Container.java:72)
        at org.mortbay.jetty.Server.main(Server.java:460)
        ... 7 more
Caused by: org.apache.commons.logging.LogConfigurationException: org.apache.commons.logging.LogConfigurationException: No suitable Log constructor [Ljava.lang.Class;@15311bd for org.apache.commons.logging.impl.Log4JLogger (Caused by java.lang.NoClassDefFoundError: org/apache/log4j/Category) (Caused by org.apache.commons.logging.LogConfigurationException: No suitable Log constructor [Ljava.lang.Class;@15311bd for org.apache.commons.logging.impl.Log4JLogger (Caused by java.lang.NoClassDefFoundError: org/apache/log4j/Category))
        at org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImpl.java:543)
        at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:235)
        at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:209)
        at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:351)
        at org.springframework.util.SystemPropertyUtils.(SystemPropertyUtils.java:42)
        ... 14 more
Caused by: org.apache.commons.logging.LogConfigurationException: No suitable Log constructor [Ljava.lang.Class;@15311bd for org.apache.commons.logging.impl.Log4JLogger (Caused by java.lang.NoClassDefFoundError: org/apache/log4j/Category)
        at org.apache.commons.logging.impl.LogFactoryImpl.getLogConstructor(LogFactoryImpl.java:413)
        at org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImpl.java:529)
        ... 18 more
Caused by: java.lang.NoClassDefFoundError: org/apache/log4j/Category
        at java.lang.Class.getDeclaredConstructors0(Native Method)
        at java.lang.Class.privateGetDeclaredConstructors(Class.java:2389)
        at java.lang.Class.getConstructor0(Class.java:2699)
        at java.lang.Class.getConstructor(Class.java:1657)
        at org.apache.commons.logging.impl.LogFactoryImpl.getLogConstructor(LogFactoryImpl.java:410)
        ... 19 more
Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Category
        at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
        ... 24 more
[shutdown output]

لقد تشغيل التطبيق مع java -verbose:class, و وفقا لهذا الإخراج ، org.أباتشي.log4j.الفئة يتم تحميلها من log4j جرة في /على شبكة الإنترنت-INF/lib فقط قبل أول طرح استثناء.

الآن إصدارات جافا على جهازين هي مختلفة قليلا.كل من آلات لدينا الشمس جافا ، لينكس آلة 1.6.0_10 ، في حين أن ويندوز آلة 1.6.0_08 ، أو ربما 07 06, لا أتذكر العدد الدقيق الآن و لا يكون الجهاز في متناول اليد.ولكن على الرغم من أن الإصدارات الثانوية من Javas هي مختلفة قليلا ، رمز لا يجب كسر مثل هذا.لا أحد فهم ما هو الخطأ هنا ؟

هل كانت مفيدة؟

المحلول

ويجب أن نفهم أن classloader لا يمكن أن نرى كل شيء. أنها يمكن أن نرى فقط ما تحميل classloader الوالدين أو ما قد حملت نفسها. حتى إذا كان لديك اثنين من classloaders، ويقول واحد لجيتي وآخر للتطبيق الويب الخاص بك، تطبيق الويب الخاص بك يمكن أن يرى log4j (منذ JAR هو WEB-INF / ليب) ولكن classloader جيتي للا يمكن.

إذا كنت تدير لجعل فئة متاحة للرصيف (على سبيل المثال شيء في طبقة DB) الذي يستخدم log4j لكن الذي ينتهي قيد التشغيل في سياق (وclassloader) من رصيف الميناء، وسوف تحصل على خطأ.

لتصحيح هذا، تعيين نقطة توقف في org.springframework.web.util.Log4jWebConfigurer.initLogging (). إذا كنت تستطيع، ونسخ مصدر هذه الفئة في المشروع (لا تنسى أن حذفها بعد ذلك) وإضافة هذا السطر:

ClassLoader cl = Thread.currentThread().getContextClassLoader();

وإلقاء نظرة على وجوه CL في المصحح الخاص بك. يجب أن أقدم لكم بعض المعلومات من إنشائه. تخميني هو أن هذا هو classloader من جيتي.

[تحرير] لاحظ أن تحصل في فوضى مختلفة إذا كان لديك log4j في كل classloaders: في هذه الحالة، سيكون لديك <م> اثنين الطبقات مع نفس الاسم الذي خلق الأشياء التي ليست مهمة متوافق! لذا تأكد من وجود مثيل واحد فقط من هذه الجرة أو أن حالات log4j لن يمر بين السياقات اثنين (التي عادة ما تكون غير ممكن).

نصائح أخرى

هذا يبدو وكأنه الكلاسيكية classloader المشكلة.يمكن أن يكون بسبب آخر تطبيق ويب يتم تحميلها الأولى التي يستخدم أيضا log4j ولكن النسخة التي هي مختلفة عن تلك المستخدمة من قبل التطبيق كنت الاختبار.Classloader يستخدم النسخة الأولى من الدرجة يجدها.فئة الملقم تحميل السياسة عادة ما يمكن أن تغير في ملفات التكوين.آسف أنا قليلا صدئ على هذا ولكن ربما أنها يمكن أن نشير لكم في الاتجاه الصحيح.

  1. تأكد من أن هناك تطبيقات أخرى مثبتة على خادم الويب ،
  2. تأكد من log4j يتم تحميلها هو الإصدار الصحيح ،
  3. تأكد من أنك لا يكون log4j الكامنة في مكان ما في classpath من الملقم.

HTH

أنت باستخدام نفس WAR على الجهازين؟ هل راجعت إذا كانت الملفات WAR متطابقة (حدثت أية أخطاء نقل)؟

وبعض الأمور عشوائية للنظر:

و(1) للتحقق ما إذا كان هناك أي إصدارات أخرى من log4j تطوف على سبيل المثال لينكس، خارج الدلائل التطبيق على شبكة الإنترنت؟

و(2) هل المشاعات اباتشي تسجيل تستخدم في كل شيء؟ قد ترغب في النظر في SLF4J بدلا من ذلك؟

و(3) هل JAR / WAR تصبح فاسدة في بعض الطريق - كان FTP'ed في ASCII أو ثنائي

و(4) طباعة التسلسل الهرمي classloader في كل حالة، فقط لمعرفة ما إذا كان هناك أي اختلافات؟

وعلى الرغم من أن تم حل المشكلة الأصلية لالسائل، وسوف نشير إلى أن مصدر مشترك للمشاكل عند تشغيل نفس رمز على ويندوز مقابل لينكس (أو يونيكس) هي القضايا حالة الحساسية. يتجاهل Windows القضية في حين لينكس أو يونكس غير لحالة الأحرف. للعض هذا لي أكثر من مرة واحدة.

وحتى إذا قمت بتحديد جرة أو دليل على CLASSPATH، لكنه ليس كذلك الحق بعد ذلك سوف تفشل على لينكس ولكن تنجح على ويندوز. هذا يمكن أن يكون أيضا مصدر FileNotFoundExceptions.

وكان نفس المشكلة وجدت حلا سهلا / الحل:

في الكسوف في تفضيلات> جافا> JREs المثبتة، حدد JRE> تحرير واضافة الجرار الخارجية ... واستعرض للوصول إلى log4j.jar الخاص بك.

والحل الآخر هو لإضافة log4j.jar إلى كل تعريف إطلاقها في التبويب CLASSPATH.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top