@Singleton
public class SingletonBean { ... }
Java Platform, Enterprise Edition (Java EE) 8 Учебник по Java EE |
Назад | Вперёд | Содержание |
Пример counter
демонстрирует, как создать сессионный компонент-синглтон.
Здесь рассматриваются следующие темы:
Аннотация javax.ejb.Singleton
используется для указания того, что класс реализации Enterprise-бина является сессионным компонентом-синглтоном:
@Singleton
public class SingletonBean { ... }
Контейнер EJB отвечает за определение того, когда инициализировать объект сессионного бина-синглтона, если только класс реализации сессионного компонента-синглтона не аннотирован javax.ejb.Startup
. В этом случае, иногда называемом ранней инициализацией, контейнер EJB должен инициализировать сессионный компонент-синглтон при запуске приложения. Сессионный компонент-синглтон инициализируется до того, как контейнер EJB доставляет клиентские запросы всем Enterprise-бинам в приложении. Это позволяет сессионному компоненту-синглтону выполнять, например, задачи запуска приложения.
Следующий сессионный компонент-синглтон хранит состояние приложения и будет инициализирован рано:
@Startup
@Singleton
public class StatusBean {
private String status;
@PostConstruct
void init {
status = "Ready";
}
...
}
Иногда для инициализации данных для приложения используются несколько сессионных EJB-компонентов, поэтому их следует инициализировать в определённом порядке. В этих случаях используйте аннотацию javax.ejb.DependsOn
для объявления зависимостей запуска сессионного компонента-синглтона. Атрибут value
аннотации @DependsOn
представляет собой одну или несколько строк, которые задают имя целевого сессионного сессионного компонента-синглтона. Если в @DependsOn
указано более одного зависимого компонента-синглтона, порядок их перечисления не обязательно является порядком, в котором контейнер EJB инициализирует целевые сессионные компоненты-синглтоны.
Так, сессионный компонент-синглтон PrimaryBean
должен быть запущен первым:
@Singleton
public class PrimaryBean { ... }
SecondaryBean
зависит от PrimaryBean
:
@Singleton
@DependsOn("PrimaryBean")
public class SecondaryBean { ... }
Это гарантирует, что контейнер EJB инициализирует PrimaryBean
раньше SecondaryBean
.
Следующий сессионный компонент-синглтон TertiaryBean
зависит от PrimaryBean
и SecondaryBean
:
@Singleton
@DependsOn({"PrimaryBean", "SecondaryBean"})
public class TertiaryBean { ... }
SecondaryBean
с помощью аннотации @DependsOn
требует, чтобы его инициализация выполнялась после инициализации PrimaryBean
. В этом случае контейнер EJB сначала инициализирует PrimaryBean
, затем SecondaryBean
и, наконец, TertiaryBean
.
Однако, если SecondaryBean
явно не зависит от PrimaryBean
, контейнер EJB может сначала инициализировать либо PrimaryBean
, либо SecondaryBean
. То есть контейнер EJB может инициализировать синглтоны в следующем порядке: SecondaryBean
, PrimaryBean
, TertiaryBean
.
Дизайн сессионных компонентов-синглтонов позволяет одновременный доступ к нему множества клиентов. Клиенту синглтона требуется только ссылка на синглтон для вызова любых бизнес-методов, предоставляемых синглтоном, и ему не нужно беспокоиться о любых других клиентах, которые могут одновременно вызывать бизнес-методы в одном и том же синглтоне.
При создании сессионного компонента-синглтона одновременный доступ к бизнес-методам синглтона можно контролировать двумя способами: параллелизм, управляемый контейнером, и параллелизм, упраляемый Managed-бином.
Аннотация javax.ejb.ConcurrencyManagement
используется для указания параллелизма, управляемого контейнером или бином, для синглтона. В @ConcurrencyManagement
атрибут типа должен быть установлен либо в javax.ejb.ConcurrencyManagementType.CONTAINER
, либо в javax.ejb.ConcurrencyManagementType.BEAN
. Если в классе реализации синглтона нет аннотации @ConcurrencyManagement
, для управления параллелизмом по умолчанию используется контейнер EJB.
Управляемый контейнером параллелизм
Если в синглтоне используется управляемый контейнером параллелизм, контейнер EJB контролирует клиентский доступ к бизнес-методам синглтона. Аннотации javax.ejb.Lock
и javax.ejb.LockType
используются для указания уровня доступа для бизнес-методов синглтона или методу @Timeout
. Значениями LockType
являются READ
и WRITE
.
Аннотируйте бизнес-метод или метод тайм-аута с помощью @Lock(LockType.READ)
, если к методу можно одновременно обращаться или совместно использовать его несколькими клиентами. Аннотируйте бизнес-метод или метод тайм-аута с помощью @Lock(LockType.WRITE)
, если сессионный компонент-синглтон должен быть заблокирован для других клиентов, пока этот метод выполняется одним из клиентов. Как правило, аннотация @Lock(LockType.WRITE)
используется, когда клиенты изменяют состояние синглтона.
Аннотирование класса синглтона с помощью @Lock
указывает, что все бизнес-методы и любые методы тайм-аута синглтона будут использовать указанный тип блокировки, если они явно не установят тип блокировки с помощью аннотации @Lock
уровня метода. Если в классе синглтона нет аннотации @Lock
, тип блокировки по умолчанию @Lock(LockType.WRITE)
применяется ко всем бизнес-методам и методам тайм-аута.
В следующем примере показано, как использовать аннотации @ConcurrencyManagement
, @Lock(LockType.READ)
и @Lock(LockType.WRITE)
для синглтона, который использует управляемый контейнером параллелизм.
Хотя по умолчанию в синглтонах используется управляемый контейнером параллелизм, аннотация @ConcurrencyManagement(CONTAINER)
может быть добавлена на уровне класса синглтона, чтобы явно установить тип управления параллелизмом:
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
@Singleton
public class ExampleSingletonBean {
private String state;
@Lock(LockType.READ)
public String getState() {
return state;
}
@Lock(LockType.WRITE)
public void setState(String newState) {
state = newState;
}
}
Метод getState
может быть доступен многим клиентам одновременно, потому что он аннотирован с помощью @Lock(LockType.READ)
. Однако когда вызывается метод setState
, все методы в ExampleSingletonBean
будут заблокированы для других клиентов, поскольку setState
помечен @Lock(LockType.WRITE)
. Это не позволяет двум клиентам одновременно пытаться изменить переменную state
в ExampleSingletonBean
.
Методы getData
и getStatus
в следующем синглтоне имеют тип READ
, а метод setStatus
имеет тип WRITE
:
@Singleton
@Lock(LockType.READ)
public class SharedSingletonBean {
private String data;
private String status;
public String getData() {
return data;
}
public String getStatus() {
return status;
}
@Lock(LockType.WRITE)
public void setStatus(String newStatus) {
status = newStatus;
}
}
Если метод имеет тип блокировки WRITE
, клиентский доступ ко всем методам синглтона блокируется до тех пор, пока текущий клиент не завершит свой вызов метода или не истечёт время ожидания доступа. По истечении времени ожидания доступа контейнер EJB выбрасывает исключение javax.ejb.ConcurrentAccessTimeoutException
. Аннотация javax.ejb.AccessTimeout
используется для указания количества миллисекунд до истечения времени ожидания доступа. Добавление @AccessTimeout
на уровне класса синглтона указывает значение времени ожидания доступа для всех методов в синглтоне, если только метод явно не переопределяет значение по умолчанию своей собственной аннотацией @AccessTimeout
.
Аннотация @AccessTimeout
может применяться к методам @Lock(LockType.READ)
и @Lock(LockType.WRITE)
. Аннотация @AccessTimeout
имеет один обязательный элемент value
и один необязательный элемент unit
. По умолчанию value
указывается в миллисекундах. Чтобы изменить единицу value
, установите для unit
одну из констант java.util.concurrent.TimeUnit
: NANOSECONDS
, MICROSECONDS
, MILLISECONDS
или SECONDS
.
В следующем синглтоне значение тайм-аута доступа по умолчанию составляет 120 000 миллисекунд или 2 минуты. Метод doTediousOperation
переопределяет время ожидания доступа по умолчанию и устанавливает значение 360 000 миллисекунд или 6 минут:
@Singleton
@AccessTimeout(value=120000)
public class StatusSingletonBean {
private String status;
@Lock(LockType.WRITE)
public void setStatus(String new Status) {
status = newStatus;
}
@Lock(LockType.WRITE)
@AccessTimeout(value=360000)
public void doTediousOperation {
...
}
}
Следующий синглтон имеет значение тайм-аута доступа по умолчанию 60 секунд, указанное с помощью константы TimeUnit.SECONDS
:
@Singleton
@AccessTimeout(value=60, unit=TimeUnit.SECONDS)
public class StatusSingletonBean { ... }
Параллелизм, управляемый Managed-бином
Синглтоны, использующие управляемый Managed-бином параллелизм, обеспечивают полный параллельный доступ ко всем бизнес-методам и методам тайм-аута в синглтоне. Разработчик синглтона отвечает за синхронизацию состояния синглтона между всеми клиентами. Разработчикам, которые создают синглтоны с управляемым бином параллелизмом, разрешается использовать примитивы синхронизации Java, такие как synchronization
и volatile
, для предотвращения ошибок при одновременном доступе.
Добавьте аннотацию @ConcurrencyManagement
с типом, установленным в ConcurrencyManagementType.BEAN
на уровне класса синглтона, чтобы указать параллелизм, управляемый Managed-бином:
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
@Singleton
public class AnotherSingletonBean { ... }
Если при инициализации контейнером EJB сессионный компонент-синглтон выдаст ошибку, он будет уничтожен.
В отличие от других Enterprise-бинов, после инициализации объекта сессионного компонента-синглтона он не уничтожается, если методы бизнес-процесса или жизненного цикла синглтона выбрасывают системные исключения. Это гарантирует, что один и тот же объект синглтона используется на протяжении всего жизненного цикла приложения.
Пример counter
состоит из сессионного компонента-синглтона CounterBean
и веб-интерфейса JavaServer Faces Facelets.
CounterBean
— это простой синглтон с одним методом getHits
, который возвращает целое число, представляющее количество обращений к веб-странице. Вот код CounterBean
:
package javaeetutorial.counter.ejb;
import javax.ejb.Singleton;
/**
* CounterBean — простой сессионный компонент-синглтон, который записывает число
* обращений к веб-странице.
*/
@Singleton
public class CounterBean {
private int hits = 1;
// Увеличить значение и вернуть результат
public int getHits() {
return hits++;
}
}
Аннотация @Singleton
помечает CounterBean
как сессионный компонент-синглтон. CounterBean
использует локальное представление без интерфейса.
CounterBean
использует значения метаданных контейнера EJB по умолчанию для синглтонов, чтобы упростить кодирование класса реализации синглтона. В классе нет аннотации @ConcurrencyManagement
, поэтому по умолчанию применяется управляемый контейнером параллельный доступ. В классе или бизнес-методе нет аннотации @Lock
, поэтому по умолчанию @Lock(WRITE)
применяется к единственному бизнес-методу getHits
.
Следующая версия CounterBean
функционально эквивалентна предыдущей версии:
package javaeetutorial.counter.ejb;
import javax.ejb.Singleton;
import javax.ejb.ConcurrencyManagement;
import static javax.ejb.ConcurrencyManagementType.CONTAINER;
import javax.ejb.Lock;
import javax.ejb.LockType.WRITE;
/**
* CounterBean — простой сессионный компонент-синглтон, который записывает число
* посещений веб-страницы.
*/
@Singleton
@ConcurrencyManagement(CONTAINER)
public class CounterBean {
private int hits = 1;
// Увеличивает значение и возвращает результат
@Lock(WRITE)
public int getHits() {
return hits++;
}
}
Веб-интерфейс counter
состоит из Managed-бина JavaServer Faces Count.java
, который используется XHTML-файлами Facelets template.xhtml
и index.xhtml
. Managed-бин JavaServer Faces Count
получает ссылку на CounterBean
посредством инъецирования зависимостей. Count
определяет свойство hitCount
JavaBeans. Когда get-метод getHitCount
вызывается из файлов XHTML, вызывается метод CounterBean
.getHits
для возврата текущего числа обращений к странице.
Вот класс Managed-бина Count
:
@Named
@ConversationScoped
public class Count implements Serializable {
@EJB
private CounterBean counterBean;
private int hitCount;
public Count() {
this.hitCount = 0;
}
public int getHitCount() {
hitCount = counterBean.getHits();
return hitCount;
}
public void setHitCount(int newHits) {
this.hitCount = newHits;
}
}
Файлы template.xhtml
и index.xhtml
используются для визуализации представления Facelets, которое отображает количество совпадений для этого представления. В файле index.xhtml
используется оператор языка выражений #{count.hitCount}
для доступа к свойству hitCount
Managed-бина Count
. Вот содержимое index.xhtml
:
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<ui:composition template="/template.xhtml">
<ui:define name="title">
This page has been accessed #{count.hitCount} time(s).
</ui:define>
<ui:define name="body">
Hooray!
</ui:define>
</ui:composition>
</html>
Вы можете использовать IDE NetBeans или Maven для сборки, упаковки, развёртывания и запуска примера counter
.
Здесь рассматриваются следующие темы:
Здесь рассматриваются следующие темы:
Удостоверьтесь, чтобы GlassFish Server был запущен (см. Запуск и остановка сервера GlassFish).
В меню «Файл» выберите «Открыть проект».
В диалоговом окне «Открыть проект» перейдите к:
tut-install/examples/ejb
Выберите каталог counter
.
Нажмите Открыть проект.
На вкладке «Проекты» кликните правой кнопкой мыши проект counter
и выберите «Выполнить».
Веб-браузер откроет URL http://localhost:8080/counter
, который отображает количество обращений.
Перезагрузите страницу, чтобы увидеть увеличение количества просмотров.
Удостоверьтесь, чтобы GlassFish Server был запущен (см. Запуск и остановка сервера GlassFish).
В окне терминала перейдите в:
tut-install/examples/ejb/counter/
Введите следующую команду:
mvn install
Эта команда собирает и развёртывает counter
в GlassFish Server.
В веб-браузере введите следующий URL:
http://localhost:8080/counter
Перезагрузите страницу, чтобы увидеть увеличение количества просмотров.
Назад | Вперёд | Содержание |