Как загрузить файл JAR во время выполнения [дубликата]

    

На этот вопрос уже есть ответ здесь:

    

Меня попросили построить систему Java, которая будет иметь возможность загружать новый код (расширения) во время работы. Как я могу повторно загрузить файл JAR, когда мой код работает? или как мне загрузить новую банку?

Очевидно, что так как постоянное время работы важно, я бы хотел добавить возможность перезагружать существующие классы во время его работы (если это не слишком усложняет).

На что мне стоит обратить внимание? (думайте об этом как о двух разных вопросах - один касается перезагрузки классов во время выполнения, другой - добавления новых классов).

72 голоса | спросил Amir Arad 12 +04002008-10-12T01:42:22+04:00312008bEurope/MoscowSun, 12 Oct 2008 01:42:22 +0400 2008, 01:42:22

5 ответов


0

Перезагрузка существующих классов с существующими данными может привести к поломке.

Вы можете относительно легко загрузить новый код в новые загрузчики классов:

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();

Загрузчики классов, которые больше не используются, можно собирать мусором (если не происходит утечка памяти, как это часто бывает при использовании ThreadLocal, драйверов JDBC, java.beans и т. д.).

Если вы хотите сохранить объектные данные, я предлагаю механизм постоянства, такой как сериализация или любой другой, к которому вы привыкли.

Конечно, системы отладки могут делать более причудливые вещи, но более хакерские и менее надежные.

Можно добавлять новые классы в загрузчик классов. Например, используя URLClassLoader.addURL. Однако если класс не загружается (например, вы его не добавили), он никогда не загрузится в этом экземпляре загрузчика классов.

ответил Tom Hawtin - tackline 12 +04002008-10-12T01:57:09+04:00312008bEurope/MoscowSun, 12 Oct 2008 01:57:09 +0400 2008, 01:57:09
0

Это работает для меня:

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");
ответил 23 MarpmMon, 23 Mar 2009 16:44:31 +03002009-03-23T16:44:31+03:0004 2009, 16:44:31
0
  

Меня попросили построить систему Java, которая будет иметь возможность загружать новый код во время работы

Возможно, вы захотите основать свою систему на OSGi (или, по крайней мере, на это), который был сделан именно для этой ситуации.

Работа с загрузчиками классов - действительно сложное дело, в основном из-за того, как работает видимость классов, и вы не хотите столкнуться с трудными для отладки проблемами позже. Например, Class.forName () , который широко используется во многих библиотеках, не слишком хорошо работает на фрагментированном пространстве загрузчика классов.

ответил Thilo 11 Jpm1000000pmSun, 11 Jan 2009 13:49:43 +030009 2009, 13:49:43
0

Я немного погуглил и нашел этот код здесь :

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);   

Может ли кто-нибудь поделиться мнениями /комментариями /ответами относительно этого подхода?

ответил Amir Arad 12 +04002008-10-12T01:55:31+04:00312008bEurope/MoscowSun, 12 Oct 2008 01:55:31 +0400 2008, 01:55:31
0

Используйте org.openide.util.Lookup и ClassLoader для динамической загрузки плагина Jar, как показано здесь.

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;
}
ответил Doan Huynh 23 Mayam12 2012, 11:09:38

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132