модульное / подключаемое Java-приложение - PullRequest
4 голосов
/ 23 июля 2011

Я пытался создать модульное веб-приложение.

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

Я использую vaadin для своего пользовательского интерфейса.И просто хотел бы, чтобы конечные пользователи предоставили файл jar или war, содержащий там пользовательский интерфейс.Однако я не хочу связывать банку внутри моего файла военных действий, все, что предоставляет конечный пользователь, должно быть развернуто как есть.

Я рассмотрел использование osgi и смог получить фреймворк, который позволяет динамический пользовательский интерфейс из комплектов, использующих vaadin, однако я иду через ад зависимости с другим требованием.Есть ли другие альтернативы, которые я не рассматривал?

Ответы [ 3 ]

4 голосов
/ 05 августа 2011

Я работал так, как хотел, используя osgi и vaadin.Я использовал этот учебник в качестве ссылки.Это дало мне половину пути к тому, что мне было нужно.

3 голосов
/ 25 июля 2011

Кажется, я делаю очень похожую вещь. Хотя в конечных компонентных инфраструктурах, таких как OSGi и платформа NetBeans (которые могут использоваться также на стороне сервера), я работаю над решением, которое я использую, и я использую его для других проектов, они платят своей сложностью, когда вы используете больше функций. которые они предлагают, помимо поиска зарегистрированных компонентов (например, принудительной проверки зависимостей, проверки версий, изоляции модулей и т. д.).

Но для сканирования связанных классов есть более простое решение, основанное на сканировании аннотаций. В моем проекте с Vaadin я создаю пользовательский интерфейс, ссылающийся на «абстрактные» имена компонентов, которые должны соответствовать фактическим классам Java, которые могут быть предоставлены пользователем.

Java-классы, реализующие компонент, отмечены пользовательской аннотацией: например,

@ViewMetadata(typeUri="component/HtmlTextWithTitle", controlledBy=DefaultHtmlTextWithTitleViewController.class)
public class VaadinHtmlTextWithTitleView extends Label implements HtmlTextWithTitleView

Затем я ищу аннотированные классы в пути к классам с помощью ClassScanner:

    final ClassScanner classScanner = new ClassScanner();
    classScanner.addIncludeFilter(new AnnotationTypeFilter(ViewMetadata.class));

    for (final Class<?> viewClass : classScanner.findClasses())
      {
        final ViewMetadata viewMetadata = viewClass.getAnnotation(ViewMetadata.class);
        final String typeUri = viewMetadata.typeUri();
        // etc...
      }

Это моя полная реализация ClassScanner, реализованная поверх Spring:

import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.ClassUtils;

public class ClassScanner 
  {
    private final String basePackage = "it"; // FIXME

    private final ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);

    @Nonnull
    public final Collection<Class<?>> findClasses() 
      {
        final List<Class<?>> classes = new ArrayList<Class<?>>();

        for (final BeanDefinition candidate : scanner.findCandidateComponents(basePackage)) 
          {
            classes.add(ClassUtils.resolveClassName(candidate.getBeanClassName(), ClassUtils.getDefaultClassLoader()));
          }

        return classes;
      }

    public void addIncludeFilter (final @Nonnull TypeFilter filter)
      {
        scanner.addIncludeFilter(filter);
      }
  }

Это очень просто, но эффективно. Обратите внимание, что из-за того, как работают Java ClassLoaders, вы должны указать хотя бы один пакет для поиска. В моем примере я установил верхний пакет «it» (мой материал - «it.tidalwave. *»), Эту информацию легко поместить в свойство, которое можно настроить, указав в итоге более одного пакета.


Другое решение может быть использовано просто с использованием двух библиотек из платформы NetBeans. Я подчеркиваю концепцию, что это не будет импортировать всю платформу в ваш проект, включая средства загрузки классов и т. Д., А будет использовать только два jar-файла. Таким образом, это не агрессивно. Это библиотеки org-openide-util.jar и org-openide-util-lookup.jar (я еще раз подчеркиваю, вы можете использовать простые файлы .jar вместо файлов .nbm, характерных для платформы NetBeans).

Обычно вы используете аннотацию @ ServiceProvider . Он запускается во время компиляции (с Java 6) и генерирует файл META-INF / services / description, который будет помещен в путь к классам. Этот файл является стандартной функцией Java (начиная с версии 1.3, я считаю) и может быть запрошен стандартным классом ServiceLoader . В этом случае вы будете использовать библиотеки платформы NetBeans только во время компиляции , потому что они используются только для генерации META-INF / services. В конце концов, библиотеки можно было бы использовать и для улучшения способов запроса зарегистрированных служб с помощью Класса поиска .

.

Между этими двумя решениями есть конструктивная разница. С моей собственной аннотацией я открываю классы: затем я использую их с отражением для создания объектов. С помощью @ServiceProvider система автоматически создает экземпляр «одиночного» объекта из класса. Таким образом, в первом случае я регистрирую классы для объектов, которые я хочу создать, во втором случае я регистрирую фабрику для их создания. В этом случае кажется, что для первого решения требуется на один проход меньше, и поэтому я его использую (обычно я часто использую @ServiceProvider).


Подводя итог, были перечислены три решения:

  1. Используйте мой прилагаемый ClassScanner с Spring. Требуется весна во время выполнения.
  2. Используйте @ServiceProvider в коде и сканируйте с помощью ServiceLoader. Требуются две библиотеки платформы NetBeans во время компиляции и только среда выполнения Java во время выполнения.
  3. Используйте @ServiceProvider в коде и сканируйте с помощью Lookup. Требуются две библиотеки платформы NetBeans во время выполнения.

Вы также можете посмотреть ответы на на этот вопрос .

1 голос
/ 23 июля 2011

Ну, раньше я использовал OSGi для большого модульного интерфейса.Мы использовали открытые социальные гаджеты, работающие внутри Shindig.OSGi хороша тем, что вы можете просто добавить дополнительные гаджеты в инфраструктуру в виде пакетов и попросить слушателя подобрать их и добавить к выбору пользовательских гаджетов.Эта модель хорошо распространяется на другие вещи, такие как темы.Какие проблемы возникают у вас с OSGi и другими зависимостями?

...