Схема побудови enterprise-додатки
Побудова Enterprise-додатки
Коли ви перший раз зустрічаєте поняття «Enterprise-додаток» або «Додаток масштабу підприємства», то зазвичай це мало що вам каже, як програмісту. Припускаю, що причина проблеми в тому, що вводиться воно в ужитку не програмістами, а маркетологами або продавцями, які найчастіше спілкуються не з розробниками, а керівниками підприємств. Навряд чи вони дадуть відповідь вам на питання «Чому JSP або Servlet відноситься до Java Enterprise Edition, а не до Java Standard Edition?». Як ви вже помітили, нічого страшного в Web-технологіях немає. Навряд чи вони виглядають набагато складніше, ніж той же Swing. Але ось розділили. З'явилися всілякі framework, які дійсно допомагають вирішувати завдання рівня Enterprise. Так що ж такого особливого є в Enterprise-додатках. На це питання я і спробую дати відповідь в цьому розділі. Можливо, хтось не погодиться з моєю думкою, але для мене важливим стало розуміння, що кожна технологія призначена для вирішення певного типу завдань. Коли вона вирішує свою задачу добре, то вона потрібна. Якщо немає - «в піч її», як казав професор Преображенський.
Якщо проаналізувати правила побудови Enterprise-додатки, то можна досить чітко зрозуміти, які бібліотеки і технології можуть бути затребувані. І їх можна навіть якось передбачити - що може знадобитися далі. Щоб довго не розтікатися мислію по древу, давайте розглянемо схему побудови Enterpise-додатки (надалі я буду говорити просто «додаток»). Не буду говорити, що вона незаперечна, але з мого досвіду під неї підходять практично всі проекти, в яких я брав участь. Та й взагалі то і не сильно вона відрізняється від рекомендацій професіоналів. Якщо розглядати специфікацію Java EE, то ідеї, закладені в ній будуть на 90% перетинатися з моїм малюнком.
Чому саме так, а не інакше?
Беручи участь не один рік (та напевно вже не одне десятиліття) в створенні систем масштабу підприємства я прийшов до загального опису, як повинно працювати Enterprise-додаток. Воно дуже просте: користувач посилає команду з параметрами, з даними щось відбувається і в результаті користувач отримує відповідь у вигляді набору якихось параметрів, які відображаються на екрані якимось чином. Я думаю, що саме це розуміння призвело до появи СОА - Сервіс-Орієнтованої Архітектури (SOA - Service Oriented Architecture). Просто це більш новий рівень того ж розуміння проблеми: користувач надсилає запит - система щось робить з цими даними і повертає якийсь результат. Те, що привнесло СОА в технологіях побудови системи - це розуміння того, що сервіси для багатьох підрозділів можуть бути однаковими, а значить, немає сенсу їх множити. І треба мати механізм, який дозволить легко підключати вже готові сервіси. Причому кожен такий сервіс може бути реалізований за тим же принципом, що і всі додаток в цілому - а саме розділене на такі ж рівні. Всі ці рівні даної архітектури просто полегшують розробку і супровід програми. Ви чіткіше розумієте, які кроки необхідно зробити, щоб користувач зміг отримати те, що йому треба. І найголовніше - тут легко враховувати специфіку Enterprise. А для таких додатків характерно наступне:
Виходячи з цих посилів, можна сказати, що додатки змушені використовувати дуже складні способи зберігання, обробки та подання інформації. І як зазвичай там, де є попит, є і пропозиція - а це не один десяток пакетів і технологій. І чим ясніше ви зможете зрозуміти задачу, чим ширше буде коло знайомих технологій, чим більша кількість пакетів вам будуть знайомі, тим швидше ви будете вирішувати проблеми клієнта і, відповідно, тим вище будуть цінувати вас як професіонала.
Схема побудови Enterprise-додатки
Єдине зауваження: дана схема призначена для побудови систем без використання головної складової СОА - ESB (Enterprise Service Bus). Якщо ж ви використовуєте СОА, то схема буде виглядати не зовсім так, але це вже «зовсім інша історія». Хоча якась частина даної схеми прекрасно може бути використана і у випадку з СОА.
Рівень зберігання даних - Persistence Layer і DataSource
Зв'язка DataSource і Persistance Layer призначена для роботи з даними. Причому дані, як видно з малюнка, можуть зберігатися не тільки в базі даних. Це може бути XML-файл або просто текстовий файл. Це може бути поштовий сервер. Або Excel-файл. Загалом це може бути все що завгодно - аби це було більш-менш постійним сховищем.
Для того, щоб можна було абстрагуватися від конкретного сховища даних застосовується таке поняття, як DataSource - джерело даних, за яким ховається зазвичай щось більш-менш відчутне - конкретна база даних, файл або ще щось. Поняття DataSource виступає в ролі такого собі моста між Persistance Layer і реальним сховищем. Насправді є навіть спеціальний клас - javax.sql.DataSource. Він исползуется для соданія конекту до бази даних - почитайте про нього, є сенс. Але крім цієї «абстракції» існує ще дуже важливий шаблон проектування - Data Access Object (DAO). Його поява пояснюється декількома причинами:
- Джерела даних можуть бути різними.
- Для доступу безпосередньо до конкретного сховища може використовуватися різний API
- Включення в логіку коду, який обмежує зміну сховища не є гарною ідеєю.
Яким же чином DAO допомагає вирішити ці проблеми. Основна ідея - визначити для Business Layer інтерфейс, який він може використовувати для доступу до даних. А вже безпосередня реалізація цього інтерфейсу буде залежати від сховища.
ORM - Object Relation Mapping. Попереджаю одразу - я не буду розглядати випадки використання будь-яких інших сховищ, крім реляційних баз даних. Але навіть в цьому випадку дані треба отримати з сховища і представити у вигляді, який зручно обробляти. Вже досить давно існує термін ORM - Object Relation Mapping. Я б перевів це як «об'єктне відображення реляційних таблиць». Хоч в оригіналі слово «таблиці» і не зустрічаються, але так буде точніше відображений сенс. Він позначає технології, які на рівні додатків дозволяють розглядати записи в таблицях, як об'єкти. Кожен рядок в таблиці - це об'єкт. Просто властивості цього класу відображаються на колонки в таблиці. Такі класи називаються Entity - Сутність. До речі, ми майже впритул підійшли до цього - ми вводили класу «Група» і «Студент», які, по суті, виконували дуже просту функцію - зберігали дані з таблиці. Дані системи беруть на себе досить нудні, але в той же час дуже важливі функції - реалізують функції CRUD (Create, Read, Update, Delete).
Вам не доводиться писати однотипний код при вставці нового запису або при отриманні даних з таблиці - напевно ви пам'ятаєте, як ми писали SQL-запити з параметрами, писали код щодо заповнення параметрів в SQL-запиті, писали код для запам'ятовування отриманих даних з ResultSetв колекції об'єктів певного типу. Цілком природно, що це незручність було помічено вже давно і були зроблені спроби якось спростити. Так з'явилися деякі framework, про які ви вже чули. Ось найбільш відомі:
- Hibernate
- TopLink
- JPA - Java Persistence API
- JDO - Java Data Object
- iBatis
Рівень бізнес-логіки - Business Layer
На цьому рівні з одного боку все дуже просто, з іншого боку - складно. Просто тому, що його ідея і функціональне призначення дійсно дуже просте - він виконує обробку даних відповідно до якоїсь логікою - змінює, додає, робить вибірку. І більше нічого. З іншого боку існує кілька складнощів. Перша - необхідно організувати роботу з даними у вигляді цілісних транзакцій (сподіваюся, що це таке ви знаєте). А друга - система може мати складну ієрархію класів, яку треба налаштовувати (ініціалізацію), що теж є не завжди тривіальним завданням.
Перша проблема досить добре вирішується декількома способами:
- EJB - Enterprise Java Beans. По суті, кожен клас (методу), який виконує будь-які дії можна привласнити транзакцію, якою управляє Application Server (не забудьте, що Application Server повинен підтримувати роботу з EJB). Вона починається при заході в метод і закінчується при виході з методу. Остання версія EJB 3.0 (якщо знову ж сервер таке підтримує) досить непогано справляється з потрібними завданнями. виходить.
- Самому чесно починати транзакції і ловити результат SQL-запитів. Цим звичайно краще не користуватися - через дерев лісу не побачите. Деяким полегшенням роботи може стати використання аспектів. Основна ідея аспектів - це щось на зразок вставки коду в різні місця програми. Наприклад, можна визначити якийсь набір методів і для них визначити дії в їх початку і наприкінці. І тоді при виклику методу буде спочатку виконуватися код аспекту і тільки після цього сам метод. Більш детально можна подивитися - Аспектно-орієнтоване програмування
- Використовувати framework Spring. Містить можливість працювати з транзакціями різних видів - звичайні JDBC-транзакції, транзакції для Hibernate, TopLink і навіть використовувати транзакції для Application Server. Річ дійсно зручна, і що дуже приємно, не вимагає Application Server - можна працювати зі звичайним web-сервером Tomcat. Що важливо відзначити, для реалізації цього Spring використовує AOP, яким володіє
Проблема ініціалізації може бути вирішена за допомогою концепції IoC (Inversion of Control). Найчастіше основним принципом називають «голлівудський принцип» - «не дзвоніть мені, я сам вам подзвоню». Іншими словами - покласти проблеми ініціалізації зв'язків між класами на framework, а не писати код ініціалізації всюди, де він буде потрібно. Для вирішення цього завдання існує чимало 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
Рівень обробки HTTP-запитів - Web Layer
Чомусь на цей рівень часто покладають управління бізнес-логікою - особливо це стосується сервлетів. На мій погляд, це не зовсім правильно.
По-перше - змішувати перетворення даних c логікою - це всі методи зібрати в одну купу і зробити смітник. А ви будете змушені це робити - адже приходять вам аж ніяк не Java-об'єкти, а звичайний HTTP. Так, звичайно, є способи це автоматизувати, але тим не менше буде це виглядати жахливо.
По-друге - хто вам сказав, що будуть ТІЛЬКИ Web-клієнти? А якщо це будуть Web-Sevices для демонів або звичайні «товсті» GUI-клієнти, які можуть спілкуватися з додатком по RMI або через ті ж самі Web-Services. Викликатимете логіку з сервлетів? В принципі можна, але це явно збільшить «помоечние» вашого коду.
Тому і народилося рішення покласти на рівень Web просту задачу перетворення даних між HTTP і Java. Єдине, що ще можна покласти на Web-рівень - це логіку зміни екранів. Той самий шаблон проектування MVC (Model-View-Controller). Але це має не дуже сильну зв'язок саме з бізнес-логікою. Що стосується технологій і framework, які можна використовувати на цьому рівні, то їх чимало:
- JSP + JSTL
- JSF
- Struts
- Spring
- і багато іншого - перераховувати складно
WS client (Web-Service client)
В общем-то тут особливо багато говорити нема про що - будуть ваші Серв використовувати якісь віддалені програми - ну і славно. Переваги і недоліки цієї технології можна пошукати в Інтернеті. Коли ми будемо описувати приклад створення такого клієнта - ми коротко торкнемося цих питань.
GUI-client
Тут все досить очевидно, хіба що протокол обміну між Application Server і клієнтом може викликати питання, але зазвичай це RMI. Що стосується реалізації безпосередньо GUI, то тут вибір за вами. На мій погляд, Swing дозволяє дуже багато. Крім цього існує SWT і море всіляких компонентів. Шукайте на просторах Інтернету.
В общем-то ніхто не заважає вам реалізувати звичайне клієнт-серверний додаток з товстим клієнтом і базою даних. Але це питання ми дуже коротко розглядали в перших частинах. Так що дивіться там і в Інтернеті.
Web-client
На сьогодні це одне з найбільш популярних рішень - але що ви будете використовувати для побудови - тут теж вибір досить великий. Зрозуміло, що якщо ви хочете, щоб UI був красивий і сучасний, то буде використовуватися AJAX. Само собою, що також вам доведеться використовувати якісь бібліотеки. Яку вибирати - вам вирішувати:
- ExtJS
- jQuery
- Dojo
- GWT
- JSF - RichFaces, IceFaces, MyFaces
- і знову ж таки багато чого ще
На що б я ще звернув увагу в даному розділі - так це на систему передачі даних від клієнта до сервера і назад. Адже ви будете використовувати HTTP, а зовсім Java-об'єкти. Тут на сьогодні вибір поки не дуже великий:
В принципі це все, що я хотів розповісти в цьому розділі. У наступній ми з вами намалюємо більш складну схему нашого відділу кадрів - щоб було цікавіше. Ви можете створювати нові - Частина 15 - нова структура даних.