هل من الممكن الحصول على تحميل ملفات System Classloader المحددة في وقت التشغيل؟

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

سؤال

أنا أكتب أداة تحليل ثابتة لمهمة، فإنها تحلل Java ByTecode باستخدام مكتبة ASM. تتطلب إحدى أجزاء ASM التي نستخدمها (أو على الأقل، تتطلب) أن يتم تحميل الفصل من الفصل الدراسي.

كنا نأمل أن تكون الأداة قادرة على تحليل ملفات .class دون الحاجة إليها على ClassPath. نحن بالفعل تحميل .classes من دليل محدد في وقت التشغيل وقراءتها باستخدام Inputstream. هذا مقبول ل ASM في معظم الحالات. هناك بعض الفصول، مثل SimpleVerifier, ، التي تحاول تحميل الفئات على الرغم من.

هل من الممكن، بموجب هذا السيناريو، لتسجيل ملفات .class المراد تحميلها بحيث تدعو Class.forName() سوف تحميلها؟ أم أن هناك طريقة سهلة لتمديد الكلمة للسماح بذلك؟


تحرير: المعلومات حول URLClassLoader كان مفيدا. لسوء الحظ، باستخدام Thread.currentThread().setContextClassLoader() لمثيل ذلك لم ينجح في هذا السيناريو. رمز المكتبة الذي استدعى فيه يستخدم أداة تحميل يسترجع على تهيئة المثيل باستخدام getClass().getClassLoader().

بحلول الوقت الذي قمت بتعيين urlclassloader، لم يتم تهيئة الفئة، لذلك أعتقد أن ContextclassLoader لا يقوم بتحميل هذه الفئة.

هل فهمت الردود بشكل صحيح؟ هل تستخدم URLClassloader لتحميل فئة الطرف الثالث احتمالا؟

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

المحلول

تقريبيا.

إذا كان لديك فصول تجميعها في مكان ما، فيمكنك تحميلها ب urlclassloader.. وبعد يمكنك بعد ذلك تعيين هذا Classloader ليكون الفصل الدراسي للمحيط الحالي: Thread.setcontextclassloader (Classloader)

يمكن للمستخدمين أن يحصلون على محمل فئة السياق الحالية واستخدام ذلك للوصول إلى تعريف الفصل.

نصائح أخرى

بادئ ذي بدء، يمكن استخدام ASM بطريقة من المحترق أنها لن تستخدم Classloader للحصول على معلومات حول الفصول الدراسية.

هناك العديد من الأماكن في إطار ASM حيث يتم تحميل الفئات بشكل افتراضي، ولكن يمكن تجاوز كل هذه الأماكن في الفئات الفرعية الخاصة بك. من أعلى رأسي:

  • classwriter.getcommonsuperclass () يتم استدعاء الأسلوب فقط عند استخدام علامة ClassWriter.comPute_Frames ويمكن الكتابة فوقها لعدم استخدام Classlader للحصول على معلومات عن الفئات. يمكنك العثور على مثال على ذلك في classwritercomputeframestest. التي تقدم تجريد classinfo
  • وبالمثل، يتم استخدام طريقة Simpleverifier.getClass () بواسطة simpleverifier.isassignablefrom () ويمكنك الكتابة فوق الأخير واستخدم التجريد ClassInfo للعثور على نوع Super Super. إذا لم أكن مخطئا، فقد نفذ مشروع JewerWerkz أمرا مشابها في رمز مطابقة نمط نوعه. لاحظ أيضا أن هناك simpleverifier.setclassloader () الطريقة، والتي يمكنك استخدامها إذا كنت لا تزال ترغب في تحميل الفصول الخاصة بك.

على ملاحظة جانبية، على JVMS JVMS، تحصل الفصول المحملة على منطقة الرجوع ولا يمكن تفريغها، لذلك ليست فكرة جيدة تحميل الفصول فقط لأغراض تحليل الرموز الثابتة فقط إذا كنت تستطيع تجنب ذلك، خاصة إذا كانت الأداة دمج في عملية حية طويلة، مثل IDE.

لا يمكنك، بقدر ما أعرف، قم بتوسيع محمل فئة النظام في وقت التشغيل، ولكن يمكنك تحميل الفئات ديناميكيا من موقع تعسفي (جرة أو دليل) باستخدام urlclassloader..

يمكنك محاولة إعداد "Launcher" في بدء تشغيل التطبيق الخاص بك الذي يخلق URLClassLoader اجتيازها المواقع على ClassPath ولها .class مواقع وبدء التطبيق من هذا الكلاس.

عندما SimpleVerifier يتم تحميلها من قبل URLClassLoader سيكون أيضا قادرا على تحميل الفئات من المواقع الإضافية.

نعم، يمكنك استخدام urlclassloader.

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

إليك الرمز.

void testHello() throws MalformedURLException, ClassNotFoundException {
    URL[] url = {
            new URL("file:/home/oreyes/testwork/")
    };

    try {
        new URLClassLoader(url).loadClass("Hello");
        throw new AssertionError("Should've thrown ClassNotFoundException");
    } catch ( ClassNotFoundException cnfe ){}


    c.process();// create the .class file 

    new URLClassLoader(url).loadClass("Hello");

    // it works!!
}

مأخوذة من هذا سؤال.

لقد أنشأت صفي الخاص بي بسيط للغاية.

 /**
 * Used to hold the bytecode for the class to be loaded.
 */
private final static ThreadLocal<byte[]> BYTE_CODE = new ThreadLocal<byte[]>();

@Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
    final byte[] bytes = BYTE_CODE.get();
    if (null == bytes) {
        throw new ClassNotFoundException(name);
    }
    return this.defineClass(null, bytes, 0, bytes.length);
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top