как загрузить файл jar во время выполнения

<p>меня попросили создать систему java, которая будет иметь возможность загружать новый код (расширения) во время работы. как я могу повторно загрузить файл jar, когда мой код работает? или как мне загрузить новую банку?</p><p>очевидно, что поскольку постоянное время работы важно, я бы хотел добавить возможность перезагружать существующие классы во время его работы (если это не слишком усложняет).</p><p>какие вещи я должен высматривать? (думайте об этом как о двух разных вопросах - один о перезагрузке классов во время выполнения, другой о добавлении новых классов).</p>

<p>перезагрузка существующих классов с существующими данными может привести к поломке.</p><p>вы можете относительно легко загрузить новый код в загрузчики новых классов:</p><pre><code>classloader loader = urlclassloader.newinstance( new url[] { yoururl }, getclass().getclassloader() ); class<?> clazz = class.forname("mypackage.myclass", true, loader); class<? extends runnable> runclass = clazz.assubclass(runnable.class); // avoid class.newinstance, for it is evil. constructor<? extends runnable> ctor = runclass.getconstructor(); runnable dorun = ctor.newinstance(); dorun.run(); </code></pre><p>загрузчики классов, которые больше не используются, могут быть собраны сборщиком мусора (если не происходит утечка памяти, как это часто бывает при использовании threadlocal, драйверов jdbc, <code>java.beans</code> и т.д.).</p><p>если вы хотите сохранить данные объекта, то я предлагаю механизм персистентности, такой как сериализация, или что вы привыкли.</p><p>конечно, системы отладки могут делать более причудливые вещи, но они более хакерские и менее надежные.</p><p>можно добавить новые классы в загрузчик классов. например, используя <code>urlclassloader.addurl</code>. однако, если класс не загружается (например, вы его не добавили), он никогда не загрузится в этот экземпляр загрузчика классов.</p>

<p>это работает для меня:</p><pre><code>file file = new file("c:\\myjar.jar"); url url = file.tourl(); url[] urls = new url[]{url}; classloader cl = new urlclassloader(urls); class cls = cl.loadclass("com.mypackage.myclass"); </code></pre>

<blockquote> <p>меня попросили создать систему java, которая будет иметь возможность загружать новый код во время работы</p> </blockquote><p>возможно, вы захотите основать свою систему на <a href="http://www.osgi.org/main/homepage">osgi</a> (или, по крайней мере, много на это), что было сделано именно для этой ситуации.</p><p>работать с загрузчиками классов действительно сложно, в основном из-за того, как работает видимость классов, и вы не хотите столкнуться с трудными для отладки проблемами позже. например, <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/class.html">class.forname ()</a> , который широко используется во многих библиотеках, не слишком хорошо работает на фрагментированном пространстве загрузчика классов.</p>

<p>я немного погуглил и нашел этот код <a href="https://community.oracle.com/message/5531305#5531305">здесь</a> :</p><pre><code>file file = getjarfiletoloadfrom(); string lcstr = getnameofclasstoload(); url jarfile = new url("jar", "","file:" + file.getabsolutepath()+"!/"); urlclassloader cl = urlclassloader.newinstance(new url[] {jarfile }); class loadedclass = cl.loadclass(lcstr); </code></pre><p>кто-нибудь может поделиться мнениями/комментариями/ответами относительно этого подхода?</p>

<p>используйте org.openide.util.lookup и classloader для динамической загрузки плагина jar, как показано здесь.</p><pre><code>public loadengine() { lookup ocrenginelookup; collection<ocrengine> ocrengines; template ocrenginetemplate; result ocrengineresults; try { //ocrenginelookup = lookup.getdefault(); this only load ocrengine in classpath of application ocrenginelookup = lookups.metainfservices(getclassloaderforextramodule());//this load the ocrengine in the extra module as well ocrenginetemplate = new template(ocrengine.class); ocrengineresults = ocrenginelookup.lookup(ocrenginetemplate); ocrengines = ocrengineresults.allinstances();//all ocrengines must implement the defined interface in ocrengine. reference to guideline of implement org.openide.util.lookup for more information } catch (exception ex) { } } public classloader getclassloaderforextramodule() throws ioexception { list<url> urls = new arraylist<url>(5); //foreach( filepath: external file *.jar) with each external file *.jar, do as follows file jar = new file(filepath); jarfile jf = new jarfile(jar); urls.add(jar.touri().tourl()); manifest mf = jf.getmanifest(); // if the jar has a class-path in it's manifest add it's entries if (mf != null) { string cp = mf.getmainattributes().getvalue("class-path"); if (cp != null) { for (string cpe : cp.split("\\s+")) { file lib = new file(jar.getparentfile(), cpe); urls.add(lib.touri().tourl()); } } } classloader cl = classloader.getsystemclassloader(); if (urls.size() > 0) { cl = new urlclassloader(urls.toarray(new url[urls.size()]), classloader.getsystemclassloader()); } return cl; } </code></pre>