Студенческий отдел кадров
Пособие по JAVA-технологиям
(с) AntonSaburov
Когда вы первый раз встречаете понятие «Enterprise-приложение» или «Приложение масштаба предприятия», то
обычно это мало что вам говорит, как программисту. Предполагаю, что причина проблемы в том, что
вводится оно в обиход не программистами, а маркетологами или продавцами, которые чаще всего общаются
не с разработчиками, а руководителями предприятий. Вряд ли они ответят вам на вопрос
«Почему JSP или Servlet относится к Java Enterprise Edition, а не к Java Standard Edition?».
Как вы уже заметили, ничего страшного в Web-технологиях нет. Вряд ли они выглядят намного сложнее,
чем тот же Swing. Но вот разделили. Появились всевозможные framework, которые действительно помогают
решать задачи уровня Enterprise. Так что же такого особенного есть в Enterprise-приложениях ? На этот
вопрос я и постараюсь дать ответ в данной главе. Возможно, кто-то не согласится с моим мнением, но для
меня важным стало понимание, что каждая технология предназначена для решения определенного типа задач.
Коли она решает свою задачу хорошо, то она нужна. Ежели нет - "в печь ее", как говаривал профессор
Преображенский.
Если проанализировать правила построения Enterprise-приложения, то можно достаточно четко понять, какие
библиотеки и технологии могут быть востребованы. И их можно даже как-то предвидеть – что может потребоваться
дальше. Чтобы долго не растекаться мыслью по древу, давайте рассмотрим схему построения Enterpise-приложения
(в дальнейшем я буду говорить просто «приложение»). Не буду говорить, что она неоспорима, но по моему опыту
под нее подходят практически все проекты, в которых я принимал участие. Да вообщем-то и не сильно она
отличается от рекомендаций профессионалов.
Участвуя не один год (да наверно уже не одно десятилетие) в создании систем масштаба предприятия я пришел к общему описанию, как должно работать Enterprise-приложение. Оно очень простое: пользователь посылает команду с параметрами, с данными что-то происходит и в итоге пользователь получает ответ в виде набора каких-то параметров, которые отображаются на экране каким-то образом. Я думаю, что именно это понимание привело к появлению СОА - Сервис-Ориентированной Архитектуры (SOA – Service Oriented Architecture). Просто это более новый уровень того же понимания проблемы: пользователь посылает запрос – система что-то делает с этими данными и возвращает какой-то результат. То, что привнесло СОА в технологиях построения системы - это понимание того, что сервисы для многих подразделений могут быть одинаковыми, а значит, нет смысла их множить. И надо иметь механизм, который позволит легко подключать уже готовые сервисы. Причем каждый такой сервис может быть реализован по тому же принципу, что и все приложение в целом – а именно разделено на такие же уровни. Все эти уровни данной архитектуры просто облегчают разработку и сопровождение приложения. Вы более четко понимаете, какие шаги необходимо предпринять, чтобы пользователь смог получить то, что ему надо. И самое главное – здесь легко учитывать специфику Enterprise. А для таких приложений характерно следующее:
Единственное замечание: данная схема предназначена для построения систем без использования главной составляющей СОА – ESB (Enterprise Service Bus). Если же вы используете СОА, то схема будет выглядеть не совсем так, но это уже «совсем другая история». Хотя какая-то часть данной схемы прекрасно может быть использована и в случае с СОА.
Связка DataSource и Persistance Layer
предназначена для работы с данными. Причем данные, как видно из рисунка, могут храниться не только
в базе данных. Это может быть XML-файл или просто текстовый файл. Это может быть почтовый сервер.
Или Excel-файл. Вообщем это может быть все что угодно – лишь бы это было более-менее постоянным
хранилищем.
Для того, чтобы можно было абстрагироваться от конкретного хранилища данных применяется такое
понятие, как DataSource – источник данных, за которым скрывается
обычно что-то более-менее осязаемое – конкретная база данных, файл или еще что-то. Понятие
DataSource выступает в роли некоего моста между Persistance Layer и
реальным хранилищем. На самом деле есть даже специальный класс –
javax.sql.DataSource. Он исползуется для содания коннекта к базе
данных – почитайте о нем, есть смысл. Но кроме этой «абстракции» существует еще очень важный шаблон
проектирования – Data Access Object (DAO). Его появление объясняется
несколькими причинами:
Рисунок показывает, что Business Layer никак не зависит от реализации
хранилища. Ему совершенно безразлично, будет ли это база данных или файл. Или просто другая база
данных. У него есть интерфес, который он использует. Если вдруг потребуется по какой-либо причине
использовать тот же MySQL вместо Oracle – вам надо только реализовать интерфейс
StudentDAO для MySQL и все. Что несомненно повышает гибкость и
переносимость системы.
По большому секрету могу сказать – принципиальная замена хранилища данных происходит крайне редко.
Например замена Oracle на MS SQL – такое я встречал. Про смену базы данных на другой источник
(например LDAP) – я такое не видел. Но тем не менее об этом шаблоне надо думать – в конце концов
при каком-нибудь слиянии или наоборот, новое руководство может в приказном порядке заставить всех
сменить хранилища данных. Например, раньше данные приходили из 1C, а сегодня руководство купило
систему «Парус» или вообще SAP. И если вы будете к этому готовы, то честь и хвала вам как профессионалу
своего дела.
Не могу не упомянуть, что в моей практике нередко случались ситуации, когда такой вариант проектирования
не требовался – в этом случае я думаю, что можно позволить себе не использовать интерфейс
StudentDAO, а проектировать сразу класс
StudentDAO. Чтобы не плодить лишние файлы. Но тут уже выбирать вам.
Что еще хотелось бы отметить – не думайте, что для всего приложения надо использовать только один DAO.
Если у вас несколько сотен таблиц и для каждой нужно как минимум 3-4 метода – то количество DAO может
(да и должно) быть больше одного. Разделение может быть разным – это и решение сделать для каждой
сущности свой DAO, и разделение по некоторому функциональному признаку (например все, что связано
со справочниками, все, что связано со счетами и т.д.) или еще как-то. Здесь сложно дать какие-либо
советы. Фантазируйте, анализируйте, пробуйте.
ORM – Object Relation Mapping. Предупреждаю сразу - я не буду рассматривать случаи
использования каких-либо иных хранилищ, кроме реляционных баз данных. Но даже в этом случае данные
надо получить из хранилища и представить в виде, который удобно обрабатывать. Уже достаточно давно
существует термин ORM – Object Relation Mapping. Я бы перевел это как «объектное отображение реляционных
таблиц». Хоть в оригинале слово «таблицы» и не встречаются, но так будет точнее отражен смысл. Он
обозначает технологии, которые на уровне приложений позволяют рассматривать записи в таблицах, как
объекты. Каждая строка в таблице – это объект. Просто свойства этого класса отображаются на колонки
в таблице. Такие классы называются Entity – Сущность. Кстати, мы почти
вплотную подошли к этому – мы вводили класса «Группа» и «Студент», которые, по сути, выполняли очень
простую функцию – хранили данные из таблицы. Данные системы берут на себя достаточно нудные, но в тоже
время очень важные функции – реализуют функции CRUD (Create, Read, Update, Delete).
Вам не приходится писать однотипный код при вставке новой записи или при получении данных из таблицы –
наверно вы помните, как мы писали SQL-запросы с параметрами, писали код по заполнению параметров в
SQL-запросе, писали код для запоминания полученных данных из ResultSet
в коллекции объектов определенного типа. Совершенно естественно, что это неудобство было замечено уже
давно и были сделаны попытки как-то упростить. Так появились некоторые framework, о которых вы уже
слышали. Вот наиболее известные:
На этом уровне с одной стороны все очень просто, с другой стороны – сложно. Просто потому, что его
идея и функциональное назначение действительно очень простое – он выполняет обработку данных в
соответствии с какой-то логикой – меняет, добавляет, делает выборку. И больше ничего. С другой
стороны существует несколько сложностей. Первая – необходимо организовать работу с данными в
виде цельных транзакций (надеюсь, что это такое вы знаете). А вторая – система может иметь сложную
иерархию классов, которую надо настраивать (инициализировать), что тоже является не всегда тривиальной
задачей.
Первая проблема достаточно хорошо решается несколькими способами:
Кроме этого чтобы еще хотелось отметить – обратите внимание, что между Persistence Layer и Business Layer
мы передаем Entity, а на другие уровни (UI уровни) BusinessLayer отдает/получает View.
Во-первых – это удобно. Надо отдавать UI то, что он будет показывать. А показывать он будет не всегда
точную структуру отношений между Entity. Значит задуматься над этим придеться – следовательно, проще
сразу предусмотреть такую возможность. Может быть, что некоторые View будут по своей структуре даже
совпадать с сущностями. Но чаще всего так не бывает.
Во-вторых – какое-то время назад мои знакомые быстренько создали Web-Sevices по структуре класса,
который отдавал наружу Entity. NetBeans честно сгенерил полное описание классов. И тут они наткнулись
на неприятное открытие. Дело в том, что сами Entity не всегда заполняются сразу полностью. Есть такое
понятие как lazy-инициализация (ленивая инициализация). Такая техника часто используется, когда вам
не нужны все поля от Entity сразу. И только когда эти данные потребуются – будет запрос к базе данных.
Но запрос может быть только когда у вас открыта транзакция. В то время, как транзакция вынесена
на бизнес-уровень, преобразование данных для передачи Web-Services производится позже – и возникает
проблема. С одной стороны Entity хочет «доинициализироваться» окончательно, а транзакция уже закрыта.
Возникает ошибка исполнения. Неудобно.
Есть еще один момент, который добавляет веса для использования View - стандартные способы
передачи параметров по HTTP (см. чуть ниже раздел "Web-client"). Для преобразования
классов из Java в какое-то текстовое представление часто используется механизм
reflection (возможность получения информации о классе - его
полях, методах и пр). Так вот при преобразовании пакеты, получая класс, пытаются разобрать
все его поля. Если какое-то поле ссылается на другой объект, пакет пытается получить доступ ко всем
полям этого объекта. И так до бесконечности. Вы наверно уже догадались, чем это может грозить, если
два объекта ссылаются друг на друга. Или в общем случае есть какая-то замкнутая цепочка объектов.
Такое преобразование просто войдет в бесконечный цикл. Можно конечно писать каждый раз свой
преобразователь. Но не проще ли написать класс для View.
Исходя из этих соображений и получается – удобно сделать отдельные классы для выдачи на уровень UI
Почему-то на этот уровень часто возлагают управление бизнес-логикой – особенно это касается сервлетов.
На мой взгляд, это не совсем правильно.
Во-первых - смешивать преобразование данных c логикой – это все методы собрать в одну кучу и сделать
помойку. А вы будете вынуждены это делать – ведь приходят вам отнюдь не Java-объекты, а обычный HTTP.
Да, конечно, есть способы это автоматизировать, но тем не менее будет это выглядеть ужасно.
Во-вторых – кто вам сказал, что будут ТОЛЬКО Web-клиенты? А если это будут Web-Sevices для демонов
или обычные «толстые» GUI-клиенты, которые могут общаться с приложением по RMI или через те же самые
Web-Services. Будете вызывать логику из сервлетов? В принципе можно, но это явно увеличит «помоечность»
вашего кода.
Поэтому и родилось решение возложить на уровень Web простую задачу преобразования данных между HTTP
и Java. Единственное, что еще можно возложить на Web-уровень – это логику смены экранов. Тот самый
шаблон проектирования MVC (Model-View-Controller). Но это имеет не
очень сильную связь именно с бизнес-логикой. Что касается технологий и framework, которые можно
использовать на этом уровне, то их немало:
Вообщем-то тут особо много говорить не о чем – будут ваши сервися использовать какие-то удаленные программы – ну и славно. Достоинства и недостатки этой технологии можно поискать в Интернете. Когда мы будем описывать пример создания такого клиента - мы вкратце коснемся этих вопросов.
Здесь все достаточно очевидно, разве что протокол обмена между Application Server и клиентом может
вызывать вопросы, но обычно это RMI. Что касается реализации непосредственно GUI, то здесь выбор
за вами. На мой взгляд, Swing позволяет очень много. Кроме этого существует SWT и море всевозможных
компонентов. Ищите на просторах Интернета.
Вообщем-то никто не мешает вам реализовать обычное клиент-серверное приложение с толстым клиентом
и базой данных. Но этот вопрос мы очень коротко рассматривали в первых частях. Так что смотрите там
и в Интернете.
На сегодня это одно из самых популярных решений – но что вы будете использовать для построения – тут тоже выбор достаточно большой. Понятно, что если вы хотите, чтобы UI был красивый и современный, то будет использоваться AJAX. Само собой, что также вам придется использовать какие-то библиотеки. Какую выбирать – вам решать:
В принципе это все, что я хотел рассказать в данной главе. В следующей мы с вами нарисуем более сложную схему нашего отдела кадров – чтобы было интереснее. Вы можете начинать - Часть 15 - новая структура данных.
Содержание