Enterprise Java Bean
является
неотъемлемой частью сервера приложений wildfly. EJB
собирает в себя всю бизнес логику приложения,
что кардинально упрощает разработку программ, при этом wildfly помогает нам с
транзакциями и управляет безопасностью EJB компонент. Перечислим все возможные компоненты EJB:
- Stateless Session Bean – сессионный компонент без сохранения состояния между вызовами методов в сессии.
- Stateful Session Bean – сессионный компонент с сохранением состояния в сессии. Состояние компонента сохраняется на протяжении одной сессии, с которой вы работаете, после окончания сессии состояние теряется.
- Message Driven Bean – компонент обработки JMS сообщений посылаемых “сервером сообщений”, допустим в wildfly встроен сервер сообщений HornetQ, можно получать от него сообщения.
- Singleton Bean – bean который реализует одноименный паттерн, такой бин существует в единственном экземпляре на сервере.
- Timer – сервисный бин, который выполняет через заданные промежутки времени, определенный код.
- Asynchronous Bean - методы этого бина выполняются асинхронно, т. е. после вызова метода бина мы, не ждем выполнения кода в методе, а сразу получаем управление в программе вызвавшей метод бина.
И так
рассмотрим простой сессионный компонент без сохранения состояния, описывая класс аннотацией @Stateless мы
говорим контейнеру, что наш класс является сессионным бином без состояния. При
создании любого класса сессионного бина, а не только Stateless, он должен удовлетворять следующим требованиям:
1. Иметь конструктор по умолчанию без параметров.
2. Класс не должен быть объявлен как final или abstract класс.
3. Поля класса
это простые типы byte, char, int, short, long их
классы обертки Byte, Character, Integer, Short, Long, тип String, временные типы -
java.util.Date, типы - java.math.BigInteger, а так же любые сериализуемые объекты,
реализующие интерфейс Serializable.
4. Должен быть хоть один public метод getters и/или setters как у любого POJO класса.
5. Методы не должны начинаться со слова ejb, например: public String ejbInit(); { … }
6. Должны присутствовать интерфейсы, помеченные
аннотацией @Local - если запускается клиент и ejb компонент на одной виртуальной машине,
допустим web
приложение, если клиент запускается на другой JVM, то нужно описать интерфейс с
аннотацией @Remote. Со
спецификации EJB 3.1 локальный
интерфейс можно опустить, по умолчанию будет пониматься, что описан бин как
локальный интерфейс, т.е. будет достаточно только аннотации @Stateless. При создании EJB c интерфейсом помеченным аннотацией @Remote возникают дополнительные затраты
для удаленного вызова методов, что утяжеляет EJB компонент и работу с ним.
И так начнем с простых вещей, с Stateless EJB. При запуске wildfly Stateless бины не создаются
по умолчанию, когда клиентское поток
запрашивает бин, wildfly его создает для нас,
после вызова метода бин не уничтожается, а “передается” в пул (free pool). Потом когда другому потоку
потребуется вызвать метод бина, он берет
из пула первый попавшийся свободный бин и вызывает его метод. Если нет
свободного бина, то создается новый, и после завершения работы метода, бин
опять таки возвращается в пул. Для того что бы пул не разросся, до больших
размеров и не потреблял много ресурсов, его
стараются ограничивать в размерах, для
этого есть специальные теги в конфигурационном файле. И так
снова обратимся к нашему старому доброму конфигурационному файлу JBOSS_HOME/Standalone/configuration/standalone.xml, добавим в него тег <stateless>
который будет ссылаться на пул "slsb-strict-max-pool" ограниченный 20 бинами:
<subsystem xmlns="urn:jboss:domain:ejb3:2.0">
<session-bean>
<stateful
default-access-timeout="5000" cache-ref="simple"
passivation-disabled-cache-ref="simple"/>
<singleton
default-access-timeout="5000"/>
<stateless>
<bean-instance-pool-ref
pool-name="slsb-strict-max-pool"/>
</stateless>
</session-bean>
<mdb>
<resource-adapter-ref
resource-adapter-name="${ejb.resource-adapter-name:hornetq-ra.rar}"/>
<bean-instance-pool-ref
pool-name="mdb-strict-max-pool"/>
</mdb>
<pools>
<bean-instance-pools>
<strict-max-pool
name="slsb-strict-max-pool" max-pool-size="20"
instance-acquisition-timeout="5"
instance-acquisition-timeout-unit="MINUTES"/>
<strict-max-pool name="mdb-strict-max-pool"
max-pool-size="20" instance-acquisition-timeout="5"
instance-acquisition-timeout-unit="MINUTES"/>
</bean-instance-pools>
</pools>
…..
После того как количество экземпляров бинов
превысит 20, параметр (max-pool-size) и все они будут заняты одновременно
обработкой запросов от потоков, и когда появиться следующий новый запрос 21-го потока
которому не хватить бина, то он запрос, не будет обрабатываться до тех пор,
пока не появятся в пуле свободный бин. До этих пор он переходит в режим “ожидания”,
время ожидания устанавливается параметром instance-acquisition-timeout 5 минут,
после этого если запрос потока все же, не получит свободный бин, будет вызван Exception. Осталось рассказать только про
жизненный цикл @Stateless
бина. И так у бина могут быть два особых метода
помеченных аннотациями @PostConstruct и @PreDestroy.
Метод помеченный аннотацией @PostConstruct
вызывается после создания бина, т.е. после выполнения конструктора, инициализации всех
полей, после выполнения dependencyInjection. Метод помеченный аннотацией @PreDestroy
выполняется при уничтожении бина. Закрепим все на примере, создадим EJB бин и JSP страницу вызывающую метод этого
бина. Начнем с maven файла 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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.vit</groupId>
<artifactId>jboss_ejb_war</artifactId>
<packaging>war</packaging>
<version>1.0</version>
<name>jboss_ejb_war</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jboss.spec.javax.ejb</groupId>
<artifactId>jboss-ejb-api_3.2_spec</artifactId>
<version>1.0.0.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.annotation</artifactId>
<version>3.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jboss-annotations-api_1.2_spec</artifactId>
<version>1.0.0.Final</version>
<scope>provided</scope>
</dependency>
</dependencies>
<repositories>
<!-- JBoss Repository
used for Java EE 6 pieces -->
<repository>
<id>repository.jboss.org</id>
<name>JBoss
Repository</name>
<url>http://repository.jboss.org/nexus/content/groups/public-jboss/</url>
</repository>
</repositories>
<build>
<finalName>jboss_ejb_war</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
Создадим stateless EJB:
package com.vit;
import org.jboss.logging.Logger;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.*;
@Stateless(name="BeanStateless")
public class SessionBean {
private
static Logger log = Logger.getLogger(SessionBean.class.getName());
private
String name = null;
public
SessionBean() {
this.name = "Hello EJB Bean";
}
public
String getName() {
return
new String(name);
}
public void
setName(String name) {
this.name = name;
}
@PreDestroy
public void
destroyInit(){
log.info(String.format("%s\n","================method
@PreDestroy call================"));
}
@PostConstruct
public void
postConstructInit(){
log.info(String.format("%s\n","================method
@PostConstruct call================"));
}
}
И
код jsp страницы:
<%@ page
contentType="text/html;charset=UTF-8" %>
<%@ page pageEncoding="UTF-8" %>
<%@ page session="false" %>
<%@ page import="com.vit.SessionBean "
%>
<%@ page import="javax.naming.Context"
%>
<%@ page
import="javax.naming.InitialContext" %>
<html>
<head>
<title>Home</title>
<meta
http-equiv="Content-Type" content="text/html;
charset=UTF-8"/>
</head>
<body>
<h1>
Hello world!</h1>
<%
Context context = new
InitialContext();
SessionBean calc = (SessionBean)
context.lookup("java:app/jboss_ejb_war/BeanStateless!com.vit.SessionBean");
calc.setName("Hello Session Stateful
Bean!!!");//пробуем перезаписать name
out.println(calc.getName()); //возвращает "Hello EJB Bean" т.к. Stateless EJB
%>
</body>
</html>
Осталось сказать, как мы получаем бин в jsp странице, для этого мы инициализируем объект Context, у которого запрашиваем через JNDI объект com.vit.SessionBean, отдельно нужно сказать про запрашиваемое имя "java:app/jboss_ejb_war/BeanStateless!com.vit.SessionBean". Если
вы не знаете, какое имя записать в методе lookup, разверните
приложение и посмотрите в логах под каким именем задеплоилось ваше EJB,
аккуратно скопируйте его. Напоминаю для того что бы развернуть приложение вы
его должны упаковать war архив и скопировать его в каталог JBOSS_HOME/Standalone/deployments.
Комментариев нет:
Отправить комментарий