Java Language
Реализации Java-плагинов
Если вы используете систему IDE и / или сборки, гораздо проще настроить такой проект. Вы создаете основной модуль приложения, затем модуль API, затем создаете модуль плагина и делаете его зависимым от модуля API или обоих. Затем вы настраиваете, где должны быть помещены артефакты проекта — в нашем случае скомпилированные плагины могут быть отправлены прямо в каталог «plugins», что позволяет избежать ручного перемещения.
Использование URLClassLoader
Существует несколько способов реализации плагиновой системы для Java-приложения. Одним из самых простых является использование URLClassLoader . В следующем примере будет задействован бит кода JavaFX.
Предположим, что у нас есть модуль основного приложения. Предполагается, что этот модуль загружает плагины в форме Jars из папки «plugins». Исходный код:
package main; public class MainApplication extends Application < @Override public void start(Stage primaryStage) throws Exception < File pluginDirectory=new File("plugins"); //arbitrary directory if(!pluginDirectory.exists())pluginDirectory.mkdir(); VBox loadedPlugins=new VBox(6); //a container to show the visual info later Rectangle2D screenbounds=Screen.getPrimary().getVisualBounds(); Scene scene=new Scene(loadedPlugins,screenbounds.getWidth()/2,screenbounds.getHeight()/2); primaryStage.setScene(scene); primaryStage.show(); >public static void main(String[] a) < launch(a); >>
Затем мы создаем интерфейс, который будет представлять собой плагин.
package main; public interface Plugin < default void initialize() < System.out.println("Initialized "+this.getClass().getName()); >default String name() >
Мы хотим загрузить классы, реализующие этот интерфейс, поэтому сначала нам нужно отфильтровать файлы с расширением «.jar»:
File[] files=pluginDirectory.listFiles((dir, name) -> name.endsWith(".jar"));
Если есть какие-либо файлы, нам необходимо создать коллекции URL-адресов и имен классов:
if(files!=null && files.length>0) < ArrayListclasses=new ArrayList<>(); ArrayList urls=new ArrayList<>(files.length); for(File file:files) < JarFile jar=new JarFile(file); jar.stream().forEach(jarEntry -> < if(jarEntry.getName().endsWith(".class")) < classes.add(jarEntry.getName()); >>); URL url=file.toURI().toURL(); urls.add(url); > >
Давайте добавим статический HashSet к MainApplication, который будет содержать загруженные плагины:
static HashSet plugins=new HashSet<>();
Затем мы создаем экземпляр URLClassLoader и повторяем имена классов, создавая экземпляры классов, которые реализуют интерфейс Plugin :
URLClassLoader urlClassLoader=new URLClassLoader(urls.toArray(new URL[urls.size()])); classes.forEach(className-> < try < Class cls=urlClassLoader.loadClass(className.replaceAll("/",".").replace(".class","")); //transforming to binary name Class[] interfaces=cls.getInterfaces(); for(Class intface:interfaces) < if(intface.equals(Plugin.class)) //checking presence of Plugin interface < Plugin plugin=(Plugin) cls.newInstance(); //instantiating the Plugin plugins.add(plugin); break; >> > catch (Exception e) >);
Затем мы можем вызвать методы плагина, например, для их инициализации:
if(!plugins.isEmpty())loadedPlugins.getChildren().add(new Label("Loaded plugins:")); plugins.forEach(plugin -> < plugin.initialize(); loadedPlugins.getChildren().add(new Label(plugin.name())); >);
Окончательный код MainApplication :
package main; public class MainApplication extends Application < static HashSetplugins=new HashSet<>(); @Override public void start(Stage primaryStage) throws Exception < File pluginDirectory=new File("plugins"); if(!pluginDirectory.exists())pluginDirectory.mkdir(); File[] files=pluginDirectory.listFiles((dir, name) ->name.endsWith(".jar")); VBox loadedPlugins=new VBox(6); loadedPlugins.setAlignment(Pos.CENTER); if(files!=null && files.length>0) < ArrayListclasses=new ArrayList<>(); ArrayList urls=new ArrayList<>(files.length); for(File file:files) < JarFile jar=new JarFile(file); jar.stream().forEach(jarEntry -> < if(jarEntry.getName().endsWith(".class")) < classes.add(jarEntry.getName()); >>); URL url=file.toURI().toURL(); urls.add(url); > URLClassLoader urlClassLoader=new URLClassLoader(urls.toArray(new URL[urls.size()])); classes.forEach(className-> < try < Class cls=urlClassLoader.loadClass(className.replaceAll("/",".").replace(".class","")); Class[] interfaces=cls.getInterfaces(); for(Class intface:interfaces) < if(intface.equals(Plugin.class)) < Plugin plugin=(Plugin) cls.newInstance(); plugins.add(plugin); break; >> > catch (Exception e) >); if(!plugins.isEmpty())loadedPlugins.getChildren().add(new Label("Loaded plugins:")); plugins.forEach(plugin -> < plugin.initialize(); loadedPlugins.getChildren().add(new Label(plugin.name())); >); > Rectangle2D screenbounds=Screen.getPrimary().getVisualBounds(); Scene scene=new Scene(loadedPlugins,screenbounds.getWidth()/2,screenbounds.getHeight()/2); primaryStage.setScene(scene); primaryStage.show(); > public static void main(String[] a) < launch(a); >>
Давайте создадим два плагина. Очевидно, что источник плагина должен быть в отдельном модуле.
package plugins; import main.Plugin; public class FirstPlugin implements Plugin < //this plugin has default behaviour >
package plugins; import main.Plugin; public class AnotherPlugin implements Plugin < @Override public void initialize() //overrided to show user's home directory < System.out.println("User home directory: "+System.getProperty("user.home")); >>
Эти плагины должны быть упакованы в стандартные Jars — этот процесс зависит от вашей среды разработки или других инструментов.
Когда Jars будут помещены в «плагины» напрямую, MainApplication обнаружит их и создаст соответствующие классы.
- Начало работы с Java Language
- 2D-графика в Java
- Apache Commons Lang
- API Reflection
- API стека
- AppDynamics и TIBCO BusinessWorks для легкой интеграции
- Autoboxing
- BigDecimal
- BigInteger
- BufferedWriter
- ByteBuffer
- CompletableFuture
- Enum, начиная с номера
- FileUpload для AWS
- FTP (протокол передачи файлов)
- HttpURLConnection
- InputStreams и OutputStreams
- Java Pitfalls — использование исключений
- Java Pitfalls — синтаксис языка
- JavaBean
- Java-агенты
- Java-версии, версии, выпуски и дистрибутивы
- JAXB
- JAX-WS
- JMX
- JNDI
- JShell
- JSON в Java
- LinkedHashMap
- log4j / log4j2
- NIO — Сеть
- NumberFormat
- ServiceLoader
- SortedMap
- Streams
- StringBuffer
- StringBuilder
- sun.misc.Unsafe
- ThreadLocal
- TreeMap и TreeSet
- Varargs (переменный аргумент)
- WeakHashMap
- XJC
- XOM — Объектная модель XML
- Альтернативные коллекции
- Анализ XML с использованием API JAXP
- Аннотации
- Апплеты
- Атомные типы
- аудио
- Безопасность и криптография
- Безопасность и криптография
- Бит-манипуляция
- Валюта и деньги
- Ведение журнала (java.util.logging)
- Видимость (контроль доступа к членам класса)
- Виртуальная машина Java (JVM)
- Виртуальный доступ Java
- Вложенные и внутренние классы
- Возможности Java SE 7
- Возможности Java SE 8
- Выбор коллекций
- Выражения
- Генерация случайных чисел
- Геттеры и сеттеры
- Даты и время (java.time. *)
- Двигатель JavaScript Nashorn
- Дженерики
- Документирование кода Java
- Загрузчики классов
- Защищенные объекты
- Изменение байтового кода
- Инкапсуляция
- Интерфейс Dequeue
- Интерфейс Java Native
- Интерфейс инструмента JVM
- Интерфейсы
- Исключения и обработка исключений
- Исполнители, Исполнительные службы и пулы потоков
- Использование ThreadPoolExecutor в приложениях MultiThreaded.
- Использование других языков сценариев в Java
- Использование ключевого слова static
- Итератор и Итерабель
- Календарь и его подклассы
- Карта Enum
- Карты
- Класс — отражение Java
- Класс EnumSet
- Класс java.util.Objects
- Класс даты
- Класс свойств
- Классы и объекты
- Клонирование объектов
- Кодировка символов
- Коллекции
- Команда Java — «java» и «javaw»
- Команды выполнения
- Компилятор Java — «javac»
- Компилятор Just in Time (JIT)
- Консольный ввод-вывод
- Конструкторы
- литералы
- Локализация и интернационализация
- Лямбда-выражения
- Массивы
- Менеджер по безопасности
- Местное время
- Местный внутренний класс
- Методы и конструкторы классов объектов
- Методы по умолчанию
- Методы сбора коллекции
- Модель памяти Java
- Модификаторы без доступа
- Модули
- наборы
- наследование
- Настройка производительности Java
- Неизменяемые объекты
- Неизменяемый класс
- Необязательный
- Новый ввод-вывод файлов
- Обработка аргументов командной строки
- Общие ошибки Java
- Одиночки
- операторы
- Операции с плавающей точкой Java
- Ориентиры
- Основные управляющие структуры
- Отправка динамического метода
- Оценка XML XPath
- Очереди и Deques
- Ошибки Java — Nulls и NullPointerException
- Ошибки Java — потоки и параллелизм
- Ошибки Java — проблемы с производительностью
- пакеты
- Параллельное программирование (темы)
- Параллельное программирование с использованием структуры Fork / Join
- Параллельные коллекции
- Перечисления
- Полиморфизм
- предпочтения
- Преобразование в строки и из них
- Преобразование типа
- Примитивные типы данных
- Процесс
- Путь Класса
- Разборка и декомпиляция
- Развертывание Java
- Разделение строки на части с фиксированной длиной
- Реализации Java-плагинов
- Регулярные выражения
- Рекурсия
- Ресурсы (на пути к классам)
- Розетки
- Свободный интерфейс
- Сериализация
- сетей
- сканер
- Служба печати Java
- Создание изображений программно
- Создание кода Java
- Сокеты Java
- Списки
- Список против SET
- Сравнение C ++
- Сравнительный и компаратор
- Ссылки на объекты
- Стандарт официального кода Oracle
- Строковый токенизатор
- Струны
- супер ключевое слово
- Тестирование устройства
- Типы ссылок
- Типы ссылочных данных
- Удаленный вызов метода (RMI)
- Управление памятью Java
- Установка Java (стандартная версия)
- Утверждая
- Файловый ввод-вывод
- Файлы с несколькими релизами JAR
- Флаги JVM
- Функциональные интерфейсы
- Хеш-таблица
- Читатели и писатели
- Шифрование RSA