سؤال

أحاول تبديل محمل الفصل في وقت التشغيل:

public class Test {
    public static void main(String[] args) throws Exception {
        final InjectingClassLoader classLoader = new InjectingClassLoader();
        Thread.currentThread().setContextClassLoader(classLoader);
        Thread thread = new Thread("test") {
            public void run() {
                System.out.println("running...");
                // approach 1
                ClassLoader cl = TestProxy.class.getClassLoader();
                try {
                    Class c = classLoader.loadClass("classloader.TestProxy");
                    Object o = c.newInstance();
                    c.getMethod("test", new Class[] {}).invoke(o);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                // approach 2
                new TestProxy().test();
            };
        };
        thread.setContextClassLoader(classLoader);
        thread.start();
    }
}

و:

public class TestProxy {
    public void test() {
        ClassLoader tcl = Thread.currentThread().getContextClassLoader();
        ClassLoader ccl = ClassToLoad.class.getClassLoader();
        ClassToLoad classToLoad = new ClassToLoad();
    }
}

(حقن classloader هل فصل يمتد org.apache.bcel.util.classloader التي ينبغي تحميل الإصدارات المعدلة من الفئات قبل أن تسأل عن الوالدين لهم)

أرغب في تحقيق نتيجة "النهج 1" و "النهج 2" نفسه تمامًا ، لكن يبدو الأمر كذلك thread.setContextClassloader (classloader) لا يفعل شيئًا ويستخدم "النهج 2" دائمًا جهاز تحميل فئة النظام (يمكن تحديده من خلال مقارنة متغيرات TCL و CCL أثناء تصحيح الأخطاء).

هل من الممكن القيام به الكل الفئات التي تم تحميلها بواسطة مؤشر ترابط جديد استخدم ClassLoader؟

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

المحلول

الفصل المجهول الذي تقوم بإنشائه عبر new Thread("test") { ... } لديه إشارة ضمنية إلى مثيل مغلق. سيتم تحميل الحرفيات الفئة داخل هذه الفئة المجهولة باستخدام محمل فئة الطبقة المرفقة.

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

    public final class MyRunnable implements Runnable {
        public void run() {
            System.out.println("running...");
            // etc...
        }
    }

    final Class runnableClass = classLoader.loadClass("classloader.MyRunnable");
    final Thread thread = new Thread((Runnable) runableClass.newInstance());

    thread.setContextClassLoader(classLoader); // this is unnecessary unless you you are using libraries that themselves call .getContextClassLoader()

    thread.start();

نصائح أخرى

أعتقد أن enjectingClassloader قد يكون مهمًا هنا. تذكر كيف يعمل Devlovation Classloading - إذا كان بإمكان أكثر من جهاز تحميل من الدرجة الأولى في التسلسل الهرمي العثور على الفصل ، فسيكون قائد الفصل الدراسي الأعلى هو الذي يتم تحميله. (انظر الشكل 21.2 هنا)

نظرًا لأن enjectingClassloader لا يحدد أحد الوالدين في مُنشئه ، فسيقوم بالتخلف عن المُنشئ في جهاز تحميل الفئة التجريدي ، والذي سيعين جهاز تحميل classloader الحالي كمصلح لـ enjectingClassLoader. لذلك ، نظرًا لأن الوالد (Context ClassLoader) يمكنه العثور على TestProxy ، فإنه دائمًا ما يحمل الفصل قبل أن يحصل حقن classloader على فرصة.

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