Подходы к проектированию J2EE приложений
Какие паттерны проектирования и фреймверки подходят оптимальным образом для вашего веб-приложения?

Перевод выполнил Беседа А.Б.

By Chris Richardson, JavaWorld.com, 01/30/06

Ссылка на источник: http://www.javaworld.com/javaworld/jw-01-2006/jw-0130-pojo.html



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

Эта статья рассматривает применение web-приложений с использованием паттернов проектирования и легковесных фреймверков. Чтобы понять какое решение использовать при создании вашего приложения, нужно будет ответить на 5 вопросов касающихся вашего приложения. Статья содержит 5 различных решений по проектированию приложения.

Бизнес-логика и доступ к данным.

Существует 2 различных пути создания веб-приложения. Один из них – использование EJB 2, как тяжеловесного подхода. В таком случае message-driven beans и session beans будут реализовывать бизнес логику. Для доступа к бизнес логики используются DAOs или entity beans. Другой вариант – использование POJO и легковесных библиотек, назовем это POJO-решением. В таком случае ваша бизнес логика будет полностью состоять из POJOs. Вы используете фреймворк для доступа к данным такой как Hibernate или JDO, и Spring для использования функций безопасности и транзакций.

Использование EJB 3 несколько усредняет эти два подхода. Entity beans являются POJO объектами и могут быть запущены внутри и снаружи контейнера. Session beans и message-driven beans также являются POJO, но имеют сложное поведение и могут быть запущены только внутри EJB контейнера. Поэтому EJB3 имеет характерные черты как и тяжеловесного компонента так и POJO.

Выбор между тяжеловесным подходом и POJO – первый из множества выборов который вам придется сделать на пути проектирования веб-приложения. Для помощи в принятии решения, какой подход выбрать, обратимся к рисунку 1, который показывает различия в данных подходах.

Рисунок 1. Архитектура приложения, решения по проектированию бизнес логики и доступа к данным.

Приложение содержит веб ориентированный уровень (presentation tier), бизнес уровень (business tier), уровень данных (persistence tier). Нам необходимо определиться со структурой бизнес уровня и интерфейсами, которые он будет предоставлять для клиентов и веб-уровня. Также надо решить как уровень представления данных, будет взаимодействовать с данными; как будет организована параллельная работа и транзакции.

Каждое из представленых на рисунке1 решений, имеет несколько вариантов. Они имеют как недостатки так и достоинства в зависимости от ситуации

Решение 1: Организация бизнес логики

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

Ключевым аспектом в данной проблеме является выбор подхода, который будет использоваться – объектный или процедурный. Это не выбор технологий, но от этого зависит организация бизнес логики. Использование EJB 2 приводит вас к процедурному проектированию.

Использование процедурного проектирования

Хотя я и являюсь приверженцем объектно-ориентированного подхода, но есть ситуации его применение является нежелательным, например при разработке небольших программ с маленькой бизнес логикой. Также если вы не имеете фреймверка для работы с данными из БД – невозможно использовать объектно-ориентированный подход. Поэтому иногда лучше написать простой транзакционный метод, для обработки запросов от уровня представления.

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

Рисунок 2. Структура процедурного подхода: большие классы транзакционных скриптов и маленькие объекты данных.

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

Использование объектно-ориентированного подхода

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

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

Такова модель представлена на рисунке 3.

Рисунок 3. Структура модели – небольшие классы содержат в себе: поведение и состояние.

Объектный подход имеет множество преимуществ, включая легкость в поддержке и дальнейшем развитии. Вы можете использовать простую объектную модель используя EJB 2 Entity Beans, но чтобы полностью воспользоваться преимуществами – используйте POJO и легковесный фреймверк, такой как Hibernate и JDO.

Решение 2: Инкапсуляция бизнес логики.

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

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

Использование шаблона EJB session facade

Классический J2EE подход инкапсулирует бизнес логику путем применения шаблона EJB session facade. EJB контейнер предоставляет функции транзакций, безопасности, распределенных транзакций, удаленного доступа. Фасад увеличивает поддержку путем инкапсуляции бизнес-логики. Уменьшение бизнес методов увеличит производительность путем минимизации количества вызовов от представления к бизнес-слою.

Рисунок 4. Инкапсулирование бизнес логики с помощью шаблона EJB Session Facade

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

К несчастью использование EJB session facade имеет значительные недостатки. EJB session beansмогут быть запущены только в EJB контейнере, что замедляет их написание и тестирование. Также разработка EJB2 и поддержка DTO (трансферных объектов), для возврата данных, скучный и затратный по времени процесс.

Использование шаблона POJO facade

Для большинства приложений, лучшим подходом является использование POJO facade в сочетании с AOP-механизмом предоставляемым Spring framework, который управляет транзакциями, безопасностью, и сохранением данных. POJO facade инкапсулирует бизнес слой в похожем стиле как и EJB session facade, и часто имеет такие же открытые методы. Отличие в том, что вместо EJB используется POJO и вместо использования EJB контейнера, который предоставляет транзакции и безопасность, используется AOP.

Рисунок 5. Инкапсуляция бизнес-логики с помощью POJO facade

Уровень представления вызывает POJO facade, который затем вызывает бизнес объекты. В таком же самом стиле как и EJB контейнер, AOP перехватывает вызовы к POJO facade и проверяет безопасность, начинает и заканчивает транзакции.

Применение POJO facade упрощает разработку тем, что вся бизнес логика может быть создана и протестирована вне сервера приложения, и предоставляя все важные преимущества of EJB session beans, такие как декларативные транзакции и безопасность. Ко все этому, вы пишете меньше кода. Вы также не должны писать много Data Transfer Objects, потому что POJO facade может возвращать domain objects слою представления, так вы можете использовать dependency injection для того чтобы связать все компоненты вместе, вместо использования запросов к JNDI.

Как всегда, существует некоторые моменты, когда не следует использовать POJO facade. Например, POJO facade не может быть использован в распределенных транзакциях инициированных удаленным клиентом.

Шаблон Exposed Domain Model

Другим недостатком использования фасада является то, что вы должны писать много лишнего кода. Кроме того, код отвечающий за возвращение объектов к слою представления особенно склонен к возникновению ошибок. Существует риск возникновения ошибок времени выполнения, возникающих из-за того что слой представления пытается получить доступ к объектам которые не были загружены в бизнес слое. Если вы используете JDO, Hibernate или EJB 3 такой проблемы можно избежать. Используется подход ленивой загрузки (lazy loading), объект будет загружен тогда, когда он понадобится.

Рисунок 6. Использование exposed domain model

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

Важным преимуществом данного подхода является устранение необходимости бизнес слоя знать какие объекты должны быть загружены и возвращены к слою представления. Но несмотря на то, что это звучит очень просто, существуют определенные недостатки. Это увеличивает сложность уровня представления, который должен управлять коннектами к БД. Управление транзакциями тоже может быть ненадежным, т.к. транзакция должна быть осуществлена до того как представление отправит любые данные браузеру.

Решение 3: Доступ к БД

Не имеет значения как вы организуете и инкапсулируете бизнес логику, в конечном счете вам придеться считывать и записывать данные в БД. Вы имеет выбор из двух инструментов: применение JDBC, которое потребует много низкоуровневого программирования или использование EJB entity beans, которые трудно использовать и содержат множество недостатков. В сравнении с ними, применение легковесного фреймверка, который позволяет использовать очень мощные средства для доступа к БД, и позволяет уменьшить количество кода.

Что неправильного в непосредственном использовании JDBC?

Потребность в объектно-реляционных фрейморвках (JDO и Hibernate) и SQL фрейморвках

iBATIS не возникла не откуда. Основой послужило разочарование в использовании JDBC. Существеут 3 проблемы при использовании JDBC:
1) Разработка и поддержка SQL трудоемкая и затратная по времени
2) Недостаток в портатируемости SQL
3) Написание JDBC кода – затратное по времени и склонное к ошибкам.

Первые 2 проблемы неизбежны, если ваше приложение должно прямо использовать SQL. Иногда необходимо использовать полную мощь SQL для получения лучшего быстродействия.

Также может потребоваться использовать полный контроль над SQL запросами, что делает невозможным использование легковесных фреймверков. Если вы имеете проблемы с прямым использование SQL, существует фреймверк iBatis, который легче использовать чем JDBC.

Использование iBATIS

Все Java приложения, которые я разрабатывал использовали SQL непосредственно. В последствии я написал мини-фреймверк, чтобы скрыть самые скучные аспекты использования JDBC. Но использование моего фреймверка как и классов Spring не решило проблему, поэтому я пришел к использованию iBATIS.

IBatis сопоставляет JavaBeans к SQL запросам используя XML дескриптор.

Использование фреймверков ORM

Такие фреймверки сопоставляют объекты к данным в БД. Автоматически загружает объекты из БД, тогда как приложения управляет отношениями между объектами и обновляет объекты в конце транзакции. Persistence фреймверк автоматически генерирует SQL используя объектно-реляционное сопоставление, которое определеяется XML файлом, где указывает как сопоставляются классы к таблицами, поля к столбцами, отношения – к таблицам и внешним ключам.

EJB 2 имеет ограниченную форму persistence framework: entity beans. Они имеют очень много недостатков, их написание и тестирование – очень сложное. Поэтому EJB 2 следует использовать как можно реже. Также еще неясно как некоторые недостатки будут связаны с EJB 3.

Существует 2 популярных легковесных persistence фреймверка – JDO от компании Sun и Hibernate – открытый проект. Они оба представляют прозрачность POJO классов. Вы можете разрабатывать и тестировать бизнес логику с использованием POJO классов не заботясь о постоянстве. Также они работают внутри и снаружи сервера приложений. Разработка с использованием Hibernate и JDO более комфортная чем со старыми EJB 2 entity beans.

Также вам необходимо определить как управлять параллелизмом в БД.

Решение 4: Управление параллельностью в транзакциях к БД

Практически все приложения имеют множество пользователей которые параллельно обновляют БД. Одновременное обращение к одним и тем же данным в БД, может нарушить их целостность. Приложения должны управлять параллельным доступом используют они легковесный фреймверк или EJB. JDO и Hibernate непосредственно поддерживают параллельные механизмы, использование их не требует очень большого количества кода.

Изолированные транзакции к БД

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

Оптимистическая блокировка (Optimistic locking)

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

Очень легко реализовать данный тип блокировки в приложениях, работающих с SQL непросредственно. Но еще легче это сделать в Hibernate и JDO, т.к. они позволяют использовать данный подход как конфигурационная опция, после этого фреймверк будет сам гененрировать SQL UPDATE запросы и проверять обновление записей.

Пессимистическая блокировка (Pessimistic locking)

Данный подход блокироует записи, что предотвращает доступ от других транзакций. Не все БД поддерживают данный тип блокировки. Этот типа блокировки поддерживается в Hibernate и JDO, через конфигурационную опцию.

Решение 5: Управление параллельностью в длительных транзакциях

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

Шаблон Optimistic Offline Lock

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

Шаблон Pessimistic Offline Lock

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