Модульні програми на java

Модульні додатки на Java. Як? +1

  • 24.03.17 2:54 •
  • jetinfosystems •
  • # 324810 •
  • Хабрахабр •
  • 42 •
  • 3800

- такий же як Forbes, тільки краще.

OSGi поспішає на допомогу


Для створення по-справжньому модульної архітектури на мові Java можна скористатися OSGi (Open Services Gateway Initiative) - специфікацією динамічної модульної системи і сервісної платформи для Java-додатків (розробник OSGi Alliance). Вона описує модель розробки ПЗ, при якій компоненти володіють трьома основними ознаками модульного додатка. Мова про інкапсуляції (кожен модуль приховує свою реалізацію від зовнішнього оточення), слабкою зв'язності (модулі взаємодіють тільки за допомогою заздалегідь обумовлених контрактів) і динамічності (компоненти можна заміщати на льоту, без зупинки всього програми). Основою концепції OSGi є 2 сутності: набори (Bundles) і сервіси (Services).


При розробці ПО на Java, як правило, використовуються сторонні бібліотеки. У світі Java-бібліотеки упаковуються в файли з розширенням JAR (Java ARchive). звичайний ZIP-архів, що містить Java-класи (файли з розширенням .class). При цьому використання бібліотек може бути пов'язане з певними складнощами.

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

Інша проблема - так званий JAR Hell, про який розробники зламали чимало списів. Суть його в наступному: як тільки ви починаєте використовувати різні версії однієї бібліотеки (таке трапляється у великих проектах, які еволюціонують з часом), ви можете зіткнутися з тим, що один і той же клас має різні методи в різних версіях бібліотеки. Java же влаштована так, що буде використана перша версія бібліотеки, яку знайде завантажувач класів. Тим самим, звернувшись в коді до якого-небудь класу під час виконання програми, ви отримаєте помилку, що метод, до якого ви звертаєтеся, не існує. Пов'язано це з тим, що на етапі виконання Java нічого не знає про версії бібліотеки, яка повинна використовуватися в тому чи іншому випадку.

Розробники OSGi не стали міняти структуру JAR-файлів для забезпечення модульності, а просто додали в них додаткову інформацію, яка використовується середовищем OSGi. Причому, інформація ця ніяк не впливає на використання JAR-файлів в звичайних Java-додатках. Отже, щоб JAR-файл став OSGi-набором, в нього додаються дані, які визначають Export-Package (пакети цього набору, доступні для використання поза ним) і Import-Package (пакети інших наборів, що вимагаються для роботи цього набору). При цьому можна задати як версію API, яку набір надає для інших наборів, так і версію або діапазон версій API, які набір вимагає для своєї роботи від них же. Всі класи набору, які не перебувають в його експортується секції, не доступні поза набору (Private). Таким способом OSGi-набір виконує вимогу слабкою зв'язності.

Сьогодні більшість Java-бібліотек вже OSGi ready, тобто містять інформацію для можливості виконання в OSGi-контейнері. Крім того є чимало інструментів і утиліт, за допомогою яких можна створити модулі для OSGi зі звичайних JAR-файлів.

Модульні програми на java


У OSGi можна легко уникати ситуацій JAR Hell, так як залежності між наборами і інтерфейси, що надаються цими наборами, мають чіткі версії. Можна динамічно завантажувати і вивантажувати нові набори під час виконання. OSGi відстежує залежності між наборами і динамічно дозволяє їх.


Отже, за допомогою OSGi-наборів ми можемо розробляти модульні додатки, які взаємодіють за допомогою інтерфейсів (API). Але де взяти клас, який реалізує необхідний інтерфейс? Варіант «додати в API набору» не підходить - в рамках модульної архітектури ми домовилися не використовувати внутрішні класи наборів поза цими наборів. Інше рішення. застосувати шаблон «фабрика», реалізуючи інтерфейс, і додати його в API набору. Але і воно не дуже вдало, тому що для приховування реалізації інтерфейсу доведеться кожного разу розробляти новий клас.

Пошук реалізації інтерфейсу в OSGi здійснюється за допомогою реєстру сервісів. У цьому реєстрі набір може зареєструвати реалізацію з описує її інтерфейсом. Набір, що використовує інтерфейс з іншого набору, може знайти в реєстрі необхідну реалізацію потрібного йому інтерфейсу. Як правило, набори реєструють сервіси при запуску в OSGi-контейнері. Плюс до всього в реєстрі сервісів можуть бути зареєстровані одні і ті ж інтерфейси з різними реалізаціями і додатковими ідентифікаційними даними. Використовуючи фільтрацію, набір може вибрати в реєстрі найбільш вподобаний з представлених сервісів.

Модульні програми на java

Мікросервіси Java Virtual Machine


Мікросервісная архітектура являє собою набір незалежних модулів - окремих додатків. Взаємодія між ними відбувається за допомогою чітко визначених інтерфейсів із застосуванням легких протоколів (REST, Protocol Buffers, MQ і т.д.). За фактом кожен модуль - це мікросервіс, що виконує одну конкретну задачу і містить, як правило, мінімальна кількість коду. Переваги цього підходу до розробки ПЗ:

  • легкість (при розробці мікросервіса реалізується лише одна частина функціональності програми).
  • простота заміни (якщо сервіс не справляється зі своїм завданням, його можна переписати і замінити на нову версію без зупинки поточного ПО).
  • повторне використання (мікросервіс може багаторазово використовуватися там, де він підходить).

Розробники модульних додатків із застосуванням OSGi давно користуються всіма цими перевагами, але тільки в рамках віртуальної машини Java. Кожен набір з OSGi, який публікує сервіс в реєстр, є мікросервісом всередині Java Virtual Machine, JVM (в світі OSGi такі мікросервіси називаються μServices).

Red Hat JBoss Fuse


Ми в «Джеті» використовуємо всі переваги OSGi при розробці ПЗ для телеком-операторів, страхових, процесингових компаній. Для цього ми застосовуємо Red Hat JBoss Fuse (конфігурація Fuse Fabric). Ця платформа надає гнучку OSGi-середовище для виконання модульного додатка.

Безперервність роботи програми, легке горизонтальне масштабування, простота розгортання, наявність засобів управління кластером для кластерного ПО - всі ці можливості доступні в Fuse Fabric. Технологія дозволяє розгорнути кілька примірників Red Hat JBoss Fuse і об'єднати їх в кластер, а також надає централізований інструмент управління вийшла середовищем.

В рамках Fuse Fabric існують такі абстракції:

Фічі (features) - сукупність OSGi-наборів, які реалізують будь-якої функціонал.
Профілі (profiles) - сукупність фич, які повинні виконуватися в рамках одного контейнера, і конфігураційні налаштування для наборів, які входять в фичу.
Контейнери (containers) - окремі JVM-процеси, які виконуються на конкретному вузлі кластера Fuse Fabric під керуванням контейнера Red Hat JBoss Fuse.

Модульні програми на java


Будь-яке ПЗ на базі технології Fuse Fabric складається з OSGi-наборів, які групуються в фичи і розгортаються в рамках будь-якого окремого JVM-процесу на одному або декількох вузлах кластера відповідно до заздалегідь заданим профілем.

Середа Fuse Fabric дає безліч інструментів для легкого управління отриманим кластером. Можна створювати профілі (а на їх основі. Контейнери), створювати / видаляти / запускати / зупиняти контейнери на будь-якому хості, що входить в кластер, підключати нові вузли кластера і т.д. І все це online - без переривання функціонування інших вузлів кластера. Є можливість зберігати кілька версій профілів, фич, OSGi-наборів.

Завдяки технології Distributed OSGi, в отриманої середовищі OSGi-набори можуть взаємодіяти в рамках як одного, так і різних контейнерів і навіть різних хостів. Додатково (при мінімальних витратах на розробку) кожен сервіс, який надає OSGi-набір, можна перетворити в REST / web-сервіс, який можна викликати з зовнішніх систем.

Таким чином, використовуючи Fuse Fabric, ми можемо створювати мікросервісную архітектуру, яка підтримує простоту настройки і розгортання, ізольоване виконання сервісів в рамках своїх JVM-процесів (зі своїми специфічними налаштуваннями, наприклад, різними настройками збирача сміття), при цьому сервіси взаємодіють між собою по мережі з використанням легкого протоколу.

Оскільки продукт Red Hat JBoss Fuse заснований на Open Source стеку технологій Apache ServiceMix, в нашому розпорядженні є такі потужні технології, як Apache ActiveMQ (реалізація специфікації JMS), Apache Camel (реалізація шаблонів інтеграції корпоративних додатків), Apache CXF (бібліотека для розробки REST / web СЕРВІС), Blueprint (надає можливості впровадження залежностей), Spring і т.д. Оскільки зазначені технології бесшовно інтегруються між собою в Red Hat JBoss Fuse, це значно знижує час розробки необхідного функціоналу.

Матеріал підготовлений експертами Центру програмних рішень компанії «Інфосистеми Джет».

А ось цікаво, як ви все це пускаєте в devmode? За стандартною схемою build-pack-deploy? Або плагін який використовуєте?
І мені здається, не зовсім аргументована модульність програми. Внутрішньо - так, має сенс для коду і тестів. Але з точки зору деплоя краще мати єдиний артефакт, ніж купу джарніков.
Якщо необхідна модульність, по-моєму краще буде розбити додаток на мікросервіси і стартувати кожен в окремій JVM / контейнері, як це робиться зараз. Єдиний сценарій, який приходить на розум - платформа для деплоя різних додатків і мікросервісов з різним циклом розробки. Щось типу ESB або AppServer. Фактично там він в осносном і використовується.

Питання щодо того, що краще, один контейнер або купа мікросервісов - він великий і заслуговує на окрему статтю. Мені давно хочеться її написати, але вона поки що вимагає обдумування.

У моєму випадку це саме не додаток, а набір модулів, які один від одного порівняно незалежні. Кожен в окремому контейнері? А заради чого? Ну тобто це риторичне питання, я і так знаю заради чого - я просто хочу зауважити, що далеко не завжди те заради чого роблять мікросервіси, має місце в житті.

Так згоден. В цьому випадку OSGi дійсно допомагає як єдина платформа для деплоя, якщо є велика кількість більш-менш незалежних модулів.

Я сам не великий фанат контейнерів і мікросервісов, оскільки в самій Java вже вбудовані непогані засоби віртуалізації. Контейнери сильно ускладнюють архітектуру і Деплой і повинні застосовуватися тільки там, де це дійсно необхідно, а не за покликом моди. Також не має сенсу штучно дробити додаток на мікросервіси, якщо у нього єдиний функціонал і цикл розробки.

І так, це в загальному-то і є ESB (шина). Тобто цикл розробки абсолютно різний, і всі разом вони ніколи не деплоятся, швидше за в одному релізі відсотків 10 в кращому випадку.

Ну і до речі, питання: а чим все-таки краще розбити на мікросервіси? Ну ось чим краще не розбивати, я спробую сформулювати:

* Централізована настройка (наприклад, на 100 модулів у нас припадає близько 20 різних баз даних, і в разі мікросервісов мені б довелося налаштовувати url / логін
пароль в 20 різних незрозумілих місцях, а так вони в одному місці.
* Централізований моніторинг (одна копія JMX, і одна Hawtio консоль, звідки видно все).
* Установка і управління з одного місця
* Один набір портів, що стирчать назовні, для всіх десятків web / rest сервісів. А точніше, один http порт і один https. І ще один набір сертифікатів в одному місці.
* Я виділив всіх сервісів скажімо 16Gb, і вони там живуть, тому що споживають пам'ять як правило в різний час і по-різному. Не факт, що це добре, але тим не менше - 100 окремим JVM довелося б тюнить параметри для кожної.

> Але з точки зору деплоя краще мати єдиний артефакт, ніж купу джарніков.

До речі, для karaf артефакт - це в тому числі і фіча (див. Вище з цього ж пості), інакше кажучи - такий xml з залежностями.

Тобто karaf просто вміє деплоіть такі ось безлічі jar-ів, взаємопов'язані один з одним. Наприклад, ви можете написати, що вам потрібна фіча «spring-jms», наприклад, яка встановиться разом з вашим модулем, і притягне з собою транзитивні залежності. Ну типу як maven, тільки в OSGI runtime. І робляться вони, до речі, з pom.xml за допомогою karaf maven plugin, не докладаючи зусиль.

Так що з точки зору деплоя ... для karaf це абсолютно пофіг.

Схожі статті