@Nick2015

Classloader и с что он собой представляет?

Доброго дня. Суть следующая есть интерфейс
public interface Module {
	public int run();
}

И 2 класса реализующих интерфейс.
  1. Как мне юзать classloader и эти классы\интерфейсы?
  2. Сам интерфейс надо же выносить в jar файл?
  3. Как мне потом сделать что б сначала вывод был с подгруженного класса 1 а потом 2, и наоборот?
  4. В нете много искал но если есть что то, то, некие екшепшены, которые скорей всего через плохое понимание структуры, как оно должно работать, что куда грузить.. Смотрел на эту статью, на словах все понятно но реализовать ее не могу :( Поэтому если не сложно поделитесь может материалом, статьями, может что провтыкал...

Меня интересует способ с общим интерфейсом....
  • Вопрос задан
  • 245 просмотров
Решения вопроса 1
vlad20012
@vlad20012
Тема с загрузкой классов уже достаточно заезжена и теория по ней гуглится легко. За пару минут нашел
официальные доки,
довольно подробная статья из кого-то блога,
запись выступления на конференции JUG.RU

Определимся с начальными условиями. Как я понял, есть папка с jar-файлами. Необходимо пройтись по всем jar-файлам и на выходе получить список классов, реализующих Module. Что-то вроде
List<Module> discoverModules(File dir) {}
Будем считать, что 1 jar-файл может содержать только один модуль (здесь и далее, "модуль" - это класс, реализующий интерфейс Module). Здесь самый нетривиальный вопрос, как этот модуль найти внутри архива. Самый простой (для начала) способ - положить в каждый jar-файл по определенному пути некий конфиг, в котором указать путь к модулю. И такой конфиг в jar-файле уже есть - стандартный META-INF. В простейшем случае у нас получается jar-файл из двух файлов с такой структурой:
MyMod.jar
├───META-INF
│   └───MANIFEST.MF
└───mymod
    └───MyMod.class

Где MANIFEST.MF содержит строчку
Main-Class: mymod.MyMod
т.е. путь к классу MyMod.

Класс MyMod нужно собирать отдельным проектом, добавляя в зависимость проект, содержащий интерфейс Module. Содержимое MyMod.java
package mymod;

public class MyMod implements Module {
    public int run() {
        System.out.println("MyMod loaded!");
    }
}

Будем считать, что MyMod.jar уже собран и лежит (возможно, вместе с другими модулями) в директории "/modules".

Ну вот, это были начальные условия =) Теперь к сути вопроса.
public class ModuleLoader {
	public static void main(String[] args) {
		List<Module> mods = new ModuleLoader().discoverModules(new File("/modules"));
		for(Module mod : mods)
			mod.run();
	}

	public List<Module> discoverModules(File dir) {
		List<File> jarFiles = Stream.of(dir.listFiles())
				.filter(f -> f.getName().endsWith(".jar"))
				.collect(Collectors.toList());
		URL[] moduleUrls = jarFiles.stream().map(this::toUrl).toArray(URL[]::new);

		URLClassLoader classLoader = new URLClassLoader(moduleUrls, getClass().getClassLoader());
		return jarFiles.stream()
				.map(this::getMainClassName)
				.map(name -> {
					try {
						return (Module) classLoader.loadClass(name).newInstance();
					} catch(Exception e) {
						throw new RuntimeException(e);
					}
				})
				.collect(Collectors.toList());
	}

	private String getMainClassName(File file) {
		try(JarFile jar = new JarFile(file)){
			return (String) jar.getManifest().getMainAttributes().get("Main-Class");
		} catch(IOException e) {
			throw new RuntimeException(e);
		}
	}

	private URL toUrl(File file) {
		try {
			return file.toURI().toURL();
		} catch(MalformedURLException e) {
			throw new RuntimeException(e);
		}
	}
}
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы