2016-01-07 2 views
7

Есть ли способ, чтобы удалить папку из аналогичных классов добавления папки во время выполнения (Can a directory be added to the class path at runtime?)Удалить папку из Java во время выполнения классов

+1

Пытались ли вы что-нибудь? Часть того, чтобы быть хорошим разработчиком, имеет желание экспериментировать и рисовать вещи для себя. Нет ничего плохого в вопросе, но это было бы намного лучше, если бы вы начали с «Вот что я пытался до сих пор, но это не сработало» ... –

+2

Хотелось бы узнать, есть ли любой сценарий реальной жизни для этого требования. – mks

+1

Я сам ничего не пробовал, а просто рылся в поисках возможных решений.Что касается реальных сценариев жизни. Я не могу дать вам сценарий производства, поскольку это будет использоваться только в наших тестовых средах. – jpints14

ответ

0

Я не думаю, что есть прямой способ сделать это. Вы можете следующим образом:

  • Получить переменные пути класса, используя: System.getenv("CLASSPATH"). Он будет возвращать значения, разделенные двоеточием.

    String classPath = System.getenv("CLASSPATH")

  • Возьмите путь к папке в качестве входных данных и заменить его "" как:

    String remainigPath = classPath.replace(inputpath,"");

  • Положите оставшиеся пути в массиве, используя метод расщепления.

    String[] paths = remainigPath .split(";");

  • Для добавления пути к классам, У вас уже есть код.

5

Ниже приведен фрагмент в качестве технического примера для демонстрации добавления/удаления пути.

создать следующие исходные файлы в любом каталоге

import java.io.File; 
import java.lang.reflect.Field; 
import java.lang.reflect.Method; 
import java.net.URL; 
import java.net.URLClassLoader; 
import java.util.Stack; 
import sun.misc.URLClassPath; 

public class EvilPathDemo { 

    public static void addPath(String path) throws Exception { 
     URL u = new File(path).toURI().toURL(); 
     URLClassLoader urlClassLoader = (URLClassLoader) 
      ClassLoader.getSystemClassLoader(); 
     Class<?> urlClass = URLClassLoader.class; 
     Method method = urlClass.getDeclaredMethod("addURL", 
       new Class[]{URL.class} 
     ); 
     method.setAccessible(true); 
     method.invoke(urlClassLoader, new Object[]{u}); 
    } 

    public static void removePath(String path) throws Exception { 
     URL url = new File(path).toURI().toURL(); 
     URLClassLoader urlClassLoader = (URLClassLoader) 
      ClassLoader.getSystemClassLoader(); 
     Class<?> urlClass = URLClassLoader.class; 
     Field ucpField = urlClass.getDeclaredField("ucp"); 
     ucpField.setAccessible(true); 
     URLClassPath ucp = (URLClassPath) ucpField.get(urlClassLoader); 
     Class<?> ucpClass = URLClassPath.class; 
     Field urlsField = ucpClass.getDeclaredField("urls"); 
     urlsField.setAccessible(true); 
     Stack urls = (Stack) urlsField.get(ucp); 
     urls.remove(url); 
    } 

    public static void main(String[] args) throws Exception { 
     String parm = args.length == 1 ? args[0] : ""; 
     String evilPath = "/tmp"; 

     String classpath = System.getProperty("java.class.path"); 
     boolean isEvilPathSet = false; 
     for (String path : classpath.split(File.pathSeparator)) { 
      if (path.equalsIgnoreCase(evilPath)) { 
       System.out.printf("evil path '%s' in classpath%n", evilPath); 
       isEvilPathSet = true; 
       break; 
      } 
     } 
     if (isEvilPathSet && parm.equalsIgnoreCase("REMOVE")) { 
      System.out.printf("evil path '%s' will be removed%n", evilPath); 
      removePath(evilPath); 
     } 
     tryToLoad("Foo"); 
     if (parm.equalsIgnoreCase("ADD")) { 
      System.out.printf("evil path '%s' will be added%n", evilPath); 
      addPath(evilPath); 
     } 
     tryToLoad("Bar"); 
    } 

    private static void tryToLoad(String className) { 
     try { 
      Class<?> foo = Class.forName(className); 
      System.out.printf("class loaded: %s%n", foo.getName()); 
     } catch (ClassNotFoundException ex) { 
      System.out.println(ex); 
     } 
    } 
} 

.

public class Foo { 
    static { 
     System.out.println("I'm foo..."); 
    } 
} 

.

public class Bar { 
    static { 
     System.out.println("I'm bar..."); 
    } 
} 

компилировать их как следовать

javac EvilPathDemo.java 
javac -d /tmp Foo.java Bar.java 

Во время теста мы будем стараться, чтобы загрузить классы Foo и Bar.

без/TMP в пути к классам

java -cp . EvilPathDemo 
java.lang.ClassNotFoundException: Foo 
java.lang.ClassNotFoundException: Bar 

добавление/TMP к классам

java -cp . EvilPathDemo add 
java.lang.ClassNotFoundException: Foo 
evil path '/tmp' will be added 
I'm bar... 
class loaded: Bar 

с/TMP в пути к классам

java -cp .:/tmp EvilPathDemo 
evil path '/tmp' in the classpath 
I'm foo... 
class loaded: Foo 
I'm bar... 
class loaded: Bar 

удалить/TMP из

классам
java -cp .:/tmp EvilPathDemo remove 
evil path '/tmp' in the classpath 
evil path '/tmp' will be removed 
java.lang.ClassNotFoundException: Foo 
java.lang.ClassNotFoundException: Bar 

Во время тестирования я обнаружил, что следующие случаи не работают.

  • addPath (evilPath);
    tryToLoad ("Foo");
    removePath (evilPath); // не влияет
    tryToLoad ("Bar");
  • removePath (evilPath);
    tryToLoad ("Foo");
    addPath (evilPath); // не имел эффекта
    tryToLoad ("Bar");
  • tryToLoad ("Foo");
    removePath (evilPath); // не имел эффекта
    tryToLoad ("Bar");

Я не потратил времени, чтобы узнать, почему. Потому что я не вижу в этом никакого практического использования. Если вам действительно нужно/хотите играть с classpaths, посмотрите, как работают загрузчики классов.

+1

Полюбите явное экспериментальное усилие, вовлеченное в этот ответ! – Stewart

4

Метод removePath сверху не работал для меня и моего контейнера Weld, стек url ​​всегда был emtpy. Следующие некрасиво самодовольны методы сработали:

public static void removeLastClasspathEntry() throws Exception { 
    URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); 
    Class<?> urlClass = URLClassLoader.class; 
    Field ucpField = urlClass.getDeclaredField("ucp"); 
    ucpField.setAccessible(true); 
    URLClassPath ucp = (URLClassPath) ucpField.get(urlClassLoader); 

    Field loadersField = URLClassPath.class.getDeclaredField("loaders"); 
    loadersField.setAccessible(true); 
    List jarEntries = (List) loadersField.get(ucp); 
    jarEntries.remove(jarEntries.size() - 1); 

    Field pathField = URLClassPath.class.getDeclaredField("path"); 
    pathField.setAccessible(true); 
    List pathList = (List) pathField.get(ucp); 
    URL jarUrl = (URL) pathList.get(pathList.size() - 1); 
    String jarName = jarUrl.toString(); 
    pathList.remove(pathList.size() - 1); 

    Field lmapField = URLClassPath.class.getDeclaredField("lmap"); 
    lmapField.setAccessible(true); 
    Map lmapMap = (Map) lmapField.get(ucp); 
    lmapMap.remove(jarName.replaceFirst("file:/", "file:///")); 
} 
1

класса погрузчики могут быть вложенными, так вместо того, чтобы модифицировать системный класс загрузчик, который является корнем дерева загрузчиков классов, то лучше просто создать вложенную загрузчик классов и использование что для загрузки классов.

Системный загрузчик классов неизменен (по уважительным причинам), но вы можете делать все, что хотите, в загрузчиках вложенных классов, включая уничтожение их для разгрузки классов и ресурсов. Это обычно используют, например, osgi и серверы приложений для загрузки/выгрузки, например. плагины, приложения и т. д.

Для вложенных загрузчиков классов вы можете полностью настроить загрузку классов. URLClassloader, вероятно, является хорошей отправной точкой для того, что вы хотите.

0

У меня была такая же проблема, поэтому я занялся ею, создав библиотеку, которая работает на каждом ClassLoader, который использует URLClassPath (так, в настоящее время, URLClassLoader).

В библиотеке есть методы:

  • Добавление новых записей перед
  • Добавляя новые записи
  • удаления существующих записей

Пожалуйста, обратите внимание, что, поскольку эта библиотека обращается к внутренней и патентованной API, в будущих версиях JDK не гарантируется работа. В настоящее время он работает для Java 7 и Java 8 (Oracle и OpenJDK).

Вот the GitHub page (вклад ценится), а вот the Maven Central artifact

+0

Просто примечание: код вдохновлен фрагментами, найденными здесь [JohannSchwarz] (http://stackoverflow.com/users/1979735/johannschwarz) и [SubOptimal] (http://stackoverflow.com/users/2333222/ субоптимальный), с небольшими изменениями, которые должны (на самом деле, незначительно) повысить надежность. –

Смежные вопросы