سؤال

كيف يمكنك تغيير CLASSPATH لعملية Java من داخل عملية Java؟


قبل أن تسألني "لماذا تريد أن تفعل ذلك؟" سأشرح ذلك قريبًا.

عندما يكون لديك Clojure REPL قيد التشغيل، فمن الشائع أن تحتاج إلى المزيد من الجرار في CLASSPATH الخاص بك لتحميل ملف كلوجر المصدر، وأرغب في القيام بذلك دون الحاجة إلى إعادة تشغيل Clojure نفسه (وهذا ليس خيارًا حقًا عند استخدامه على Slime on Emacs).

هذا هو السبب ولكني لا أريد أن يتم وضع علامة على هذا السؤال على أنه محرر غريب بعض اللغات وأن يتم تجاهله من قبل غالبية مطوري Java الذين قد يكون لديهم الإجابة.

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

المحلول

تحديث الربع الرابع 2017:مثل علق أدناه بواسطة vda8888, ، في Java 9، النظام java.lang.ClassLoader لم يعد أ java.net.URLClassLoader.

يرى "دليل الهجرة لجافا 9:التحديات السبعة الأكثر شيوعا"

يتم تنفيذ إستراتيجية تحميل الفئة التي وصفتها للتو في نوع جديد وفي Java 9 يكون مُحمل فئة التطبيق من هذا النوع.
وهذا يعني أنه ليس أ URLClassLoader بعد الآن، وبالتالي في بعض الأحيان (URLClassLoader) getClass().getClassLoader() أو (URLClassLoader) ClassLoader.getSystemClassLoader() لن يتم تنفيذ التسلسلات بعد الآن.

java.lang.ModuleLayer سيكون نهجا بديلا يستخدم من أجل التأثير على معرف com لهذا التطبيق هو com.modulepath (بدلاً من مسار الفصل).انظر على سبيل المثال "وحدات Java 9 - أساسيات JPMS".


لجافا 8 أو أقل:

بعض التعليقات العامة:

لا يمكنك (بطريقة محمولة ومضمونة العمل، انظر أدناه) تغيير مسار فئة النظام.بدلاً من ذلك، تحتاج إلى تحديد ClassLoader جديد.

تعمل ClassLoaders بطريقة هرمية...لذا فإن أي فئة تقوم بمرجع ثابت للفئة X يجب تحميلها في نفس ClassLoader مثل X، أو في ClassLoader الفرعي.لا يمكنك استخدام أي ClassLoader مخصص لتحميل التعليمات البرمجية بواسطة رابط ClassLoader الخاص بالنظام بشكل صحيح، إذا لم يكن قد فعل ذلك من قبل.لذلك تحتاج إلى الترتيب لتشغيل رمز التطبيق الرئيسي الخاص بك في ClassLoader المخصص بالإضافة إلى الكود الإضافي الذي تحدد موقعه.
(ما قيل، تصدع كل شيء يذكر في التعليقات هذا المثال من تمديد URLClassLoader)

وقد تفكر في عدم كتابة ClassLoader الخاص بك، ولكن فقط استخدم URLClassLoader بدلاً من ذلك.قم بإنشاء URLClassLoader باستخدام عنوان url لا في عنوان URL الخاص بأداة تحميل الفصل الأصلي.

URL[] url={new URL("file://foo")};
URLClassLoader loader = new URLClassLoader(url);

أ حل أكثر اكتمالا سيكون:

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

// Add the conf dir to the classpath
// Chain the current thread classloader
URLClassLoader urlClassLoader
 = new URLClassLoader(new URL[]{new File("mtFile").toURL()},
                      currentThreadClassLoader);

// Replace the thread classloader - assumes
// you have permissions to do so
Thread.currentThread().setContextClassLoader(urlClassLoader);

إذا افترضت أن أداة تحميل فئة نظام JVMs هي URLClassLoader (وهذا قد لا يكون صحيحًا بالنسبة لجميع JVMs)، فيمكنك استخدام الانعكاس أيضًا لتعديل مسار فئة النظام فعليًا...(ولكن هذا اختراق؛)):

public void addURL(URL url) throws Exception {
  URLClassLoader classLoader
         = (URLClassLoader) ClassLoader.getSystemClassLoader();
  Class clazz= URLClassLoader.class;

  // Use reflection
  Method method= clazz.getDeclaredMethod("addURL", new Class[] { URL.class });
  method.setAccessible(true);
  method.invoke(classLoader, new Object[] { url });
}

addURL(new File("conf").toURL());

// This should work now!
Thread.currentThread().getContextClassLoader().getResourceAsStream("context.xml");

نصائح أخرى

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

ليست هناك حاجة لكتابة محمل الفصل الخاص بك! هناك clojure.lang.dynamicclassloader.

http://blog.japila.pl/2011/01/dynamally-redefining-classpath-in-clojure-repl/

قد ترغب في البحث في استخدام java.net.urlclassloader. يسمح لك بتحميل الفصول برمجيًا لم تكن في الأصل في ClassPath ، على الرغم من أنني لست متأكدًا مما إذا كان هذا بالضبط ما تحتاجه.

من الممكن كما هو موضح من الرابطين أدناه ، يبدو أن الطريقة التي يعطيها Vonc هي الأفضل ولكن تحقق من بعض هذه المنشورات وجوجل لـ "Java Dynamic Classpath" أو "Java Dynamic Class Loading" ومعرفة بعض المعلومات من هناك.

كنت أنشر بتعمق أكثر ولكن Vonc قد قامت بالمهمة.

من التحميل الديناميكي لملفات الفصل وجرة.

تحقق أيضا من هذا Sun Forum Post.

String s="java  -classpath abcd/ "+pgmname+" "+filename;   
Process pro2 = Runtime.getRuntime().exec(s); 
BufferedReader in = new BufferedReader(new InputStreamReader(pro2.getInputStream()));

هو مثال على Changin the ClassPath في برنامج Java

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