JavaRush /Java блог /Random UA /Знайомство з EJB
Анзор Кармов
31 рівень
Санкт-Петербург

Знайомство з EJB

Стаття з групи Random UA
У цій статті розглянемо EJB – Enterprise JavaBeans. Ця технологія є частиною специфікації Java EE. Ми торкнемося таких питань, як:
  • що таке EJB;
  • якою є історія виникнення EJB;
  • які є типи EJB.
А ще – напишемо невеликий HelloWorld додаток з використанням EJB та сервлетів. Знайомство з EJB-1Ця стаття виявиться корисною для читачів, які освоїлися в Java SE і починають вивчення Java EE. Для повноцінного розуміння практичної частини цієї статті рекомендується спершу ознайомитися із статтею " Налаштування локального оточення ".

Коротка історія EJB

У далекому 1996 році, коли автору цієї статті було 5 років, Java вже мала популярність серед розробників. Причиною тому були доброзичливі API, автоматичне складання сміття, і т.д. Java широко використовувалася в системах, що відповідали за бекенд. Однак, незважаючи на всі принади мови, програмісти того часу потребували певного функціоналу, ще не реалізованого в JDK. Такими потребами були:
  • забезпечення персистентності даних;
  • цілісність транзакцій
  • конкурентний доступ до даних (управління багатопоточністю);
  • і, швидше за все, ще щось.
Усе це призводило до природного зростання популяції доморощених, самописних, закритих бібліотек. Іншими словами, кожен реалізовував свої потреби як міг. Так тривало доти, доки IBM у 1997 році не виступила з гаслом: "Всі повинні реалізовувати свої потреби однаково", і не випустила специфікації Enterprise Java Bean (EJB). Саме вона дозволила уніфікувати процес розробки та взяти рішення типових проблем (описаних вище як потреби) на бік фреймворку. Компанія Sun займалася адаптацією дітища IBM протягом 2 років, і в 1999 випустила специфікацію EJB 1.0. Так з'явилася на світ технологія, про яку далі йтиметься у прикладнішому ключі.

Що таке EJB

EJB у певному сенсі — збірний термін, який в залежності від контексту може мати на увазі під собою або саму технологію Enterprise JavaBeans загалом, або деякий конкретний програмний компонент (бін) Enterprise JavaBean, який є частиною технології EJB. Визначення EJB як технології наводиться на вікіпедії: Enterprise JavaBeans (також часто використовується у вигляді абревіатури EJB) - специфікація технології написання та підтримки серверних компонентів, що містять бізнес-логіку. Є частиною Java EE. Ця технологія зазвичай застосовується, коли бізнес-логіка вимагає щонайменше один з наступних сервісів, а часто всі з них:
  • підтримка безпеки даних (persistence): дані повинні бути в безпеці навіть після зупинки програми. Найчастіше досягається з використанням бази даних;
  • підтримка розподілених транзакцій;
  • підтримка паралельної зміни даних та багатопоточність;
  • підтримка подій;
  • підтримка іменування та каталогів (JNDI);
  • безпека та обмеження доступу до даних;
  • підтримка автоматизованої установки на сервер додатків;
  • віддалений доступ.
Перераховані вище сервіси — це безперечна перевага технології EJB. Ще однією такою перевагою є те, що все перераховане вище працює з коробки, відразу ж. Тобто. програмісту не треба думати про підтримку розподілених транзакцій. Програмістові потрібно думати тільки про бізнес-логіку, яку він намагається реалізувати. EJB як деякий конкретний програмний компонент - це Java-клас з однією або декількома анотаціями зі специфікації EJB, який містить деяку бізнес логіку програми. Інструкції зі специфікації EJB наділяють позначений клас певними повноваженнями, силами, суперздібностями. Докладніше про це читайте нижче.

Типи EJB

Резюмуємо. EJB - це звичайний Java клас, відзначений однією зі спеціальних анотацій. Такі класи називають бінами. Залежно від того, якою анотацією відзначений клас, він буде представником того чи іншого типу EJB (бінів). Є три основні типи бінів:
  • Message Driven Beans (біни, керовані повідомленнями);
  • Entity Beans (об'єктні біни) – визначені у специфікації JPA (Java Persistence API) та використовуються для зберігання даних;
  • Session Beans (сесійні біни).
Останні (сесійні біни) поділяються на кілька підвидів:
  • stateless (без стану);
  • stateful (за допомогою поточного стану сесії);
  • singleton (один об'єкт на всю програму; починаючи з версії EJB 3.1).
Знайомство з EJB - 2Нижче розглянемо кожен тип бінів докладніше.

Session Beans

Session Beans, або сесійні біни – певний вид бінів. Вони інкапсулюють у собі бізнес-логіку, яку клієнт може програмно викликати через виклик методів цього бина. Виклик методу може виконати:
  • локально, іншим класом у тій же JVM, як і сесійний бін;
  • віддалено, через мережу, з іншої JVM, за допомогою технології Java RMI (Remote Method Invocation).
Слово «сесійний» передбачає, що бін доступний лише тимчасово виконання певної завдання сервером і безповоротно знищується у разі аварії чи зупинки сервера. Життєвий цикл екземпляра сесійного бина управляється EJB контейнером (докладніше про EJB контейнери можна почитати у першій лекції циклу ). Сесійні біни без стану (stateless)не зберігають інформацію про свій стан. Компонент такого типу можна використовувати різними клієнтами. Stateless біни використовуються для реалізації бізнес-процесів, які можна завершити за одну операцію. Наприклад, перевірка кредитної історії клієнтів. Оскільки один екземпляр біна може бути використаний різними клієнтами, розробник повинен забезпечити безпечний доступ до даних біна. Створити бін такого типу (втім, як і решта всіх сесійних бін) досить просто. Це звичайний Java-клас з інструкцією @Stateless. Наведемо приклад нижче:
import javax.ejb.Stateless;

@Stateless
public class StatelessEjbExample {
    public String sayHi() {
        return "Hi, I'm Stateless EJB!";
    }
}
Сесійні біни з підтримкою поточного стану сесії (Stateful) зберігають інформацію про свій стан між зверненнями до нього від одного й того самого клієнта та завершують своє існування за явним запитом від клієнта. Досягається це за рахунок того, що статеві біни унікальні для кожного клієнта. Приклад завдання, за яке може відповідати такий тип бінів, - підтримка в актуальному стані кошика покупок в інтернет-магазині для кожного користувача. Життєвим циклом цих бінів управляє контейнер EJB. Ці біни також знищуються, коли клієнт завершує свою роботу. Подібні біни теж досить просто творити. Це Java клас, позначений інструкцією Stateful. Приклад нижче:
import javax.ejb.Stateful;

@Stateful
public class StatefulEjbExample {
    public String sayHi() {
        return "Hi, I,m Stateful EJB";
    }
}
Сесійні біни одинаки (singleton) ініціюються один раз за час існування програми та існують весь час "життя" програми. Такі біни розробляються для ситуацій, у яких один стан має бути поділений між усіма клієнтами. Подібно до stateless бінам, в бінах одиночках розробнику необхідно стежити за організацією потокобезпечного середовища всередині бина. Наведемо приклад Singleton Біна, який також простий у створенні як і його побратими, про які йшлося вище. Неважко здогадатися, що це Java-клас з інструкцією @Singleton. Однак у разі необхідно бути уважним. Є дві інструкції, ідентичні за синтаксисом, але різні за призначенням і розташовані в різних пакетах:
  • javax.ejb.Singleton
  • javax.inject.Singleton
Для створення EJB необхідно використовувати інструкцію з пакета javax.ejb. Приклад нижче:
import javax.ejb.Singleton;

@Singleton
public class SingletonEjbExample {
    public String sayHi() {
        return "Hi, I'm Singleton EJB!";
    }
}

Message Driven Beans

Message Driven Beans, або MDB, або біни керовані повідомленнями, подібно до сеансових бін реалізують деяку бізнес-логіку. Але, на відміну від своїх родичів, у MDB є одна важлива відмінність. Клієнти ніколи не викликають методи MDB безпосередньо. Такі біни найчастіше виступають у ролі слухачів JMS (Java Message Service) повідомлень і є для організації асинхронного обміну повідомленнями між частинами системи. Прикладом такого повідомлення є запит на доставку товарних запасів від автоматизованої системи роздрібної торгівлі до системи управління поставками. Нижче наведемо приклад MDB Біна. На відміну від сесійних бінів, його створення трохи цікавіше:
import javax.annotation.Resource;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenContext;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

@MessageDriven(mappedName = "jms/TestQueue")
public class MessageDrivenEjbExample implements MessageListener {

    @Resource
    private MessageDrivenContext messageDrivenContext;

    public void onMessage(Message message) {
        try {
            if (message instanceof TextMessage) {
                TextMessage msg = (TextMessage) message;
                msg.getText();
            }
        } catch (JMSException e) {
            messageDrivenContext.setRollbackOnly();
        }
    }

}
Анотація MessageDrivenробить наш клас MDB біном. Усередині анотації за допомогою JNDI (читайте про JNDI тут ) визначається ім'я JMS розсилки, слухачем якої стає наш клас. Крім цього, наш клас реалізує інтерфейс MessageListenerта його метод onMessage. Даний метод буде викликаний, коли прийде деяке повідомлення із черги/розсилки з ім'ям, визначеним усередині анотації MessageDriven.

Entity beans

Частиною технології EJB є JPA специфікація. JPA, або Java Persistence API – це специфікація, яка забезпечує об'єктно-реляційне відображення (ORM – Object-Relational Mapping) Java об'єктів (Entity бінів) та надає API для збереження, отримання та управління такими об'єктами. JPA дозволяє подавати дані з БД у вигляді Java-об'єктів, а також зберігати Java-об'єкти у вигляді записів у базі даних. У ролі подібного об'єкта може виступати не кожен клас, а саме Entity біни. Entity Bean - це Java клас, який відображає деяку таблицю в базі даних. Відображення (мапінг) досягається за рахунок використання спеціальних анотацій. З їхньою допомогою здійснюється зіставлення Java-класу з таблицею у базі даних, і навіть зіставлення полів Java-класу з полями таблиці БД. Наведемо приклад Entity Біна,
@Entity // Делает данный класс Entity бином
@Table(name = "employee") // "Связывает" данный класс с таблицей employee в БД
public class Employee implements Serializable {

    @Id // Говорит о том, что поле ниже является первичным ключом
    @GeneratedValue(strategy = GenerationType.AUTO) // Определяет тип генерации значений первичного ключа
    private int id;

    @Column(name="name") // "Связывает" поле ниже с полем name в таблице employee в БД
    private String name;

    @Column (name="age") // "Связывает" поле ниже с полем age в таблице employee в БД
    private int age;

    // getters and setters...
}
Варто зазначити, що цей тип бінів має сенс вивчати лише у контексті вивчення специфікації JPA.

Пишемо додаток: EJB HelloWorld

У цьому розділі ми напишемо невелику Java EE HelloWorld програму, яку розгорнемо на сервері GlassFish. Перед прочитанням цієї статті настійно рекомендується прочитати статтю про налаштування локального оточення .
  1. Створюємо новий Maven проект у IntelliJ IDEA.

    File -> New -> Project...

    Знайомство з EJB - 3
  2. Натискаємо Next .

  3. Заповнюємо параметри Maven проекту:

    Знайомство з EJB - 4
  4. Натискаємо Finish

  5. Проект створено та має таку структуру:

    Знайомство з EJB-5
Файл pom.xml виглядає так: Знайомство з EJB-6Насамперед нам необхідно додати залежність від Java EE API, а також вказати упаковку нашого проекту у вигляді архіву веб-додатку (war). Щоб зробити це, необхідно привести код pom.xml до такого вигляду:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.codegym.lectures</groupId>
    <artifactId>ejb_demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
        </dependency>
    </dependencies>

</project>
Далі можна розпочинати Java-код. Наш додаток буде найпростішим. У нас буде 1 сервлет та 1 EJB. Це буде сесійний бін без збереження стану (stateless). Усередині EJB ми визначимо лише один метод, який повертатиме рядок “Hello World”. Насамперед створимо пакет com.codegym.lectures. Потім, усередині пакету com.codegym.lectures, створимо наш бін – DemoEJB. Код біна наведено нижче:
import javax.ejb.Stateless;

@Stateless
public class DemoEJB {
    public String helloWorld() {
        return "Hello world!";
    }
}
Як було сказано раніше, все досить просто. Наш наступний крок — створити сервлет, який передаватиме значення з EJB як відповідь на HTTP-запит. Варто зазначити, що сервлети не належать до теми цієї статті, але для демонстрації EJB все ж таки доведеться їх використовувати. Для цього створимо новий сервлет DemoServletу тому пакеті, що і EJB. Його код нижче:
@WebServlet("/helloWorld")
public class DemoServlet extends HttpServlet {

    @EJB
    private DemoEJB ejb;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write(ejb.helloWorld());
    }
}
Наведемо невеликі коментарі до коду. Анотація @WebServlet("/helloWorld")— визначає наш клас як сервлет, який оброблятиме HTTP запити на ендпоінт /helloWorld. У нашого класу є одне поле DemoEJB ejb. Це наш бін, визначений раніше. Анотація над полем класу @EJBздійснює ін'єкцію залежності (DI). Тобто. Змінна ejb автоматично ініціалізується новим екземпляром, коли це буде потрібно. Наш клас є спадкоємцем HttpServlet і перевизначає один із методів суперкласу - doGet. Даний метод обробляє HTTP GET запити і приймає два параметри - HttpServletRequestі HttpServletResponse. HttpServletRequestслужить для отримання інформації про запит, що надійшов HTTP. HttpServletResponseнеобхідний формування відповіді запит. Всередині методу ми отримуємо об'єкт PrintWriterу об'єкта відповіді (HttpServletResponse), за допомогою методу getWriter(). Далі ми можемо записати в отриманий об'єкт деяке значення за допомогою методу write. Чим, власне, ми і користуємося, записуючи в об'єкт PrintWriter-а значення, отримане з визначеного нами EJB (значення - рядок "Hello World!"). Дане значення клієнт, який надіслав HTTP-запит, отримає як відповідь на свій запит. Наступним кроком є ​​запуск програми на Java EE сервері GlassFish. Для цього створимо нову конфігурацію, як описано в статті про налаштування локального оточення . Нижче скрін готової конфігурації для поточного проекту. Переконайтеся, що у вас встановлено сервер GlassFish перед запуском: Знайомство з EJB-7Після створення конфігурації запуску - запускаємо програму за допомогою меню Run -> Run 'ejb_demo' або за допомогою хоткеюShift+F10 . Після запуску можна побачити його логи: Знайомство з EJB-8А також браузер, що відкрився: Знайомство з EJB-9Все це говорить про те, що додаток працює, як замислювалося.

Висновок

У цій статті ми знайомабося з EJB – Enterprise JavaBeans. Розглянули такі питання, як:
  • Що таке EJB?
  • Історія EJB
  • Різні типи EJB
Згадаймо, що EJB бувають таких типів:
  • Message Driven Beans (біни, керовані повідомленнями);
  • Entity Beans (об'єктні біни) - визначені в специфікації JPA (Java Persistence API) entities та використовуються для зберігання даних;
  • Session Beans (сесійні біни):
    • stateless (без стану)
    • stateful (за допомогою поточного стану сесії)
    • singleton (один об'єкт на всю програму; починаючи з версії EJB 3.1)
А також ми написали невелику HelloWorld програму з використанням EJB. Як ДЗ ти можеш повторити практичну частину цієї статті самостійно. А потім додати в свою програму ще два сервлети, які будуть використовувати stateful і singleton бини для отримання значення.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ