Расширяемое/адаптируемое приложение Java EE: интерфейсы против перехватчиков и декораторов

В настоящее время мы изучаем технические требования для новой версии приложения Java EE. Это Java EE 6, но переход на 7 - это вариант. До сих пор это было одно приложение, одно EAR, предлагающее четко определенные функции. Тем не менее, ему необходимо определить определенную функциональность очень определенным образом на основе проекта реализации и/или клиента.

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

В связи с этим необходимо иметь архитектуру, которая определяет общие функции, но имеет подключаемые части, а также возможность расширения. Для некоторых аспектов я имею общее представление о том, как это можно было бы обработать. У этого вопроса есть ответ, который отлично подходит для слоя презентации, который мы будем делать в JSF 2: Как создать модульное приложение JSF 2.0?

Я менее уверен в уровне бизнес-логики, безопасности и т.д. Моя первоначальная идея состояла в том, чтобы определить интерфейсы (пару фасадов) и найти реализацию во время выполнения или время развертывания. Во многом так же, как механизм поставщика услуг. Может быть предложена реализация по умолчанию, с возможностью определения пользовательской. Это действительно похоже на решение Java SE, и мне интересно, применяю ли я только те концепции, которые мне знакомы в этом контексте, и если нет ничего лучше для EE. Я думаю, что аннотация @Alternative служит такой цели.

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

Может ли кто-нибудь дать представление о том, какое решение лучше всего для какой части этой задачи? Должен ли я объединить эти методы для различных частей проблемной области? Есть ли возможности, которые я не вижу?

Важное требование: мы хотим сохранить код, специфичный для отдельного клиента/проекта. Мы не хотим иметь полную версию приложения под контролем версий для каждой реализации, поскольку это быстро станет кошмаром обслуживания. В идеале, также не нужно было бы строить это как монолитный EAR, но иметь возможность добавлять подключаемые части в какую-либо папку lib или разворачивать их отдельно.

Ответ 1

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

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

Первоначальный дизайн очень важен, и речь идет не только об основных понятиях, таких как interfaces. Пожалуйста, не пойми меня неправильно. Интерфейсы важны, но я бы предпочел использовать немного другую терминологию - contracts или extension points

enter image description here

Предположим, что вы правильно определили extension points. Что вы будете делать дальше? Я бы сказал, что в конце концов вы реализуете какой-то plugin framework. (Вы можете потратить час, чтобы играть с JSPF и посмотреть, как он упрощает разработку модульных приложений и поощряет ослабленная муфта).

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

enter image description here

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

В конце концов вы придумаете модули life-cycle, чтобы определить все важные аспекты. Например:

enter image description here

Мое предложение - не изобретать колесо. OSGi может быть хорошим решением для вас. Также обратите внимание на то, что OSGi хороша, зрелая и обеспечивает много вещей из коробки, но она также несколько сложна:

enter image description here

Таким образом, вам определенно потребуется некоторое время, чтобы исследовать его немного глубоко. Также проверьте следующее: Какие преимущества предоставляет система компонентов OSGi?

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

Обновление

Хорошо, принимая во внимание приведенное ниже обсуждение, я бы предложил следующее:

Заключение

Извините за длинный ответ, но я должен убедиться, что за ним стоит ясный и логичный момент. Ваше первоначальное намерение на 100% правильное и хорошее. Лучше определить интерфейсы/контракты и скрыть всю сложность. Это именно то, о чем идет ООП.

В любом случае, самая важная задача - не создавать хороший дизайн, а сохранять его с течением времени. Мое предложение состоит в том, чтобы обеспечить хороший дизайн, используя слабосвязанный подход с того же самого начала. Сервис Locator patter - это то, что вам действительно нужно.

enter image description here

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

Если у вас достаточно уверенности, пропустите Service Locator и перейдите на Dependency Injection. Дополнительная информация: Fowler по вступлению зависимостей против локатора сервисов

Ответ 2

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

Я использовал этот подход в прошлом, хотя и с одной базой кода.

Ответ 3

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

Ответ 4

Вы исследовали шаблон стратегии? Звучит так же, как и то, что вы ищете. Это позволяет вашему коду выбирать поведение во время выполнения без использования экземпляра класса или сложного класса. Вот пример, и вот полная статья:

public interface ShippingMethod {
    public double getShippingCost(double weightInPounds, double distanceInMiles);
}

public class FirstClassShipping implements ShippingMethod {
    public double getShippingCost(double weightInPounds, double distanceInMiles) {
        // Calculate the shipping cost based on USPS First class mail table
    }
}

public class FedExShipping implements ShippingMethod {
    public double getShippingCost(double weightInPounds, double distanceInMiles) {
        // Calculate the shipping cost based on FedEx shipping
    }       
}

public class UPSShipping implements ShippingMethod {
    public double getShippingCost(double weightInPounds, double distanceInMiles) {
        // Calculate the shipping cost based on UPS table
    }       
}

public class ShippingInfo {

    private Address address;
    private ShippingMethod shippingMethod;

    public Address getAddress() {
        return this.address;
    }

    public double getShippingCost(double weightInPounds, double distanceInMiles) {
        return shippingMethod.getShippingCost(weightInPounds, distanceInMiles);
    }
}

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

Ответ 5

Вы можете предоставить REST для всех своих функций, и вы можете определить CLI (интерфейс командной строки) поверх этого REST для более безопасных клиентов. Вы используете тот же REST, если хотите создать интерфейс браузера. Расширяясь, вам нужно только документировать, когда разрабатывается новый API (вызов REST) ​​(добавляется в ходу). В этом ядре вы можете перейти на любой уровень безопасности, настроив параметры доступа через систему j2ee. Я вообще не эксперт j2ee, но я думаю, что вы на самом деле ищете лучший дизайн для интерфейсного приложения для jee.

JERSEY имеет четкую функциональность для маршалинга по проводам. Если вы объедините jaxb с этим, я думаю, вам понравится. Создайте клуб с помощью JMS для обновлений службы.