Давайте расскажем об основанных на Java архитектурах веб-приложений!
Для веб-приложений существует множество различных архитектур, которые должны быть реализованы с использованием Java. Ответами на этот вопрос могут служить библиотеки различных дизайнов веб-приложений со своими плюсами и минусами. Хотя я понимаю, что ответы будут субъективными, давайте постараемся быть максимально объективными и мотивировать перечисленные плюсы и минусы.
Используйте уровень детализации, который вы предпочитаете для описания вашей архитектуры. Чтобы ваш ответ имел какую-либо ценность, вам, по крайней мере, придется описать основные технологии и идеи, используемые в описываемой вами архитектуре. И последнее, но не менее важное, когда мы должны использовать вашу архитектуру?
Я начну...
Обзор архитектуры
Мы используем трехуровневую архитектуру, основанную на открытых стандартах Sun, таких как Java EE, Java Persistence API, Servlet и Java Server Pages.
- Упорство
- Бизнес
- презентация
Возможные коммуникационные потоки между уровнями представлены:
Persistence <-> Business <-> Presentation
Что, например, означает, что уровень представления никогда не вызывает и не выполняет операции персистентности, он всегда делает это через бизнес-уровень. Эта архитектура предназначена для удовлетворения требований веб-приложения высокой доступности.
Упорство
Выполняет операции сохранения , чтения, обновления и удаления ( CRUD ). В нашем случае мы используем ( Java Persistence API ) JPA, и в настоящее время мы используем Hibernate в качестве нашего поставщика сохраняемости и используем его EntityManager .
Этот уровень разделен на несколько классов, где каждый класс имеет дело с определенным типом сущностей (то есть сущности, связанные с корзиной покупок, могут обрабатываться одним классом постоянства) и используется одним и только одним менеджером .
Кроме того, в этом слое также хранятся объекты JPA , такие как Account
и ShoppingCart
т. Д.
Бизнес
Вся логика, которая связана с функциональностью веб-приложения, находится на этом уровне. Эта функция может инициировать перевод денег для клиента, который хочет оплатить продукт в режиме онлайн с помощью своей кредитной карты. С таким же успехом это может быть создание нового пользователя, удаление пользователя или вычисление исхода битвы в сетевой игре.
Этот уровень разделен на несколько классов, и каждый из этих классов помечается, @Stateless
чтобы стать компонентом сеанса без сохранения состояния (SLSB). Каждый SLSB называется менеджером, и, например, менеджер может быть аннотированным классом, как указано выше AccountManager
.
Когда AccountManager
необходимо выполнить операции CRUD, он делает соответствующие вызовы экземпляру класса AccountManagerPersistence
, который является постоянным уровнем. Примерный набросок двух методов AccountManager
может быть:
...
public void makeExpiredAccountsInactive() {
AccountManagerPersistence amp = new AccountManagerPersistence(...)
// Calls persistence layer
List<Account> expiredAccounts = amp.getAllExpiredAccounts();
for(Account account : expiredAccounts) {
this.makeAccountInactive(account)
}
}
public void makeAccountInactive(Account account) {
AccountManagerPersistence amp = new AccountManagerPersistence(...)
account.deactivate();
amp.storeUpdatedAccount(account); // Calls persistence layer
}
Мы используем транзакции диспетчера контейнеров, поэтому нам не нужно проводить разграничение транзакций самостоятельно. В сущности, что происходит внутри, мы инициируем транзакцию при входе в метод SLSB и фиксируем ее (или выполняем откат) непосредственно перед выходом из метода. Это пример соглашения по конфигурации, но нам пока что не нужно ничего, кроме значения по умолчанию, Требуется.
Вот как в руководстве по Java EE 5 от Sun объясняется обязательный атрибут транзакции для Enterprise JavaBeans (EJB):
Если клиент работает в транзакции и вызывает метод корпоративного компонента, метод выполняется в транзакции клиента. Если клиент не связан с транзакцией, контейнер запускает новую транзакцию перед запуском метода.
Атрибут Required является неявным атрибутом транзакции для всех методов корпоративного компонента, работающих с разграничением транзакций, управляемым контейнером. Обычно вы не устанавливаете атрибут Required, если вам не нужно переопределять другой атрибут транзакции. Поскольку атрибуты транзакции являются декларативными, вы можете легко изменить их позже.
презентация
Наш уровень представления отвечает за ... представление! Он отвечает за пользовательский интерфейс и показывает информацию пользователю, создавая HTML-страницы и получая пользовательский ввод через запросы GET и POST. В настоящее время мы используем старую комбинацию Servlet + Java Server Pages ( JSP ).
Уровень вызывает методы в менеджерах бизнес-уровня для выполнения операций, запрошенных пользователем, и получения информации для отображения на веб-странице. Иногда информация, полученная от бизнес-уровня, представляет собой менее сложные типы, такие как String
s и int
egers, а в других случаях объекты JPA .
Плюсы и минусы с архитектурой
Pros
- Наличие всего, что связано с определенным способом сохранения в этом слое, означает только то, что мы можем перейти от использования JPA к чему-то другому, без необходимости что-либо переписывать на бизнес-уровне.
- Нам легко поменять наш уровень презентации на что-то другое, и, скорее всего, мы это сделаем, если найдем что-то лучшее.
- Позволить контейнеру EJB управлять границами транзакций - это хорошо.
- Использовать Servlet + JPA легко (для начала), а технологии широко используются и применяются на многих серверах.
- Предполагается, что использование Java EE облегчит нам создание системы высокой доступности с балансировкой нагрузки и переключением при сбое . Оба из которых мы чувствуем, что мы должны иметь.
Cons
- Используя JPA, вы можете хранить часто используемые запросы как именованные запросы, используя
@NamedQuery
аннотацию к классу сущностей JPA. Если у вас как можно больше связано с постоянством в классах постоянства, как в нашей архитектуре, это будет распространяться на места, где вы можете также найти запросы для включения сущностей JPA. Будет сложнее рассмотреть операции сохранения и, следовательно, сложнее поддерживать. - У нас есть сущности JPA как часть нашего уровня постоянства. Но
Account
иShoppingCart
разве они не являются бизнес-объектами? Это делается так, как вы должны прикоснуться к этим классам и превратить их в сущности, с которыми JPA знает, как обращаться. - Объекты JPA, которые также являются нашими бизнес-объектами, создаются как объекты передачи данных ( DTO ), также известные как объекты значений (VO). Это приводит к анемичной модели предметной области, поскольку у бизнес-объектов нет собственной логики, кроме методов доступа. Вся логика выполняется нашими менеджерами на бизнес-уровне, что приводит к более процедурному стилю программирования. Это не хороший объектно-ориентированный дизайн, но, может быть, это не проблема? (В конце концов, объектная ориентация - не единственная парадигма программирования, которая дала результаты.)
- Использование EJB и Java EE представляет некоторую сложность. И мы не можем использовать чисто Tomcat (добавление EJB-микроконтейнера - это не просто Tomcat).
- Есть много проблем с использованием Servlet's + JPA. Используйте Google для получения дополнительной информации об этих проблемах.
- Поскольку транзакции закрываются при выходе из бизнес-уровня, мы не можем загрузить любую информацию из сущностей JPA, которая настроена для загрузки из базы данных, когда она необходима (используется
fetch=FetchType.LAZY
), из уровня представления. Это вызовет исключение. Перед возвратом объекта, содержащего поля такого типа, мы должны обязательно вызвать соответствующий получатель. Другой вариант - использовать язык запросов постоянства Java ( JPQL ) и выполнить команду aFETCH JOIN
. Однако оба эти варианта немного громоздки.