Выбрать главу
Листинг 2.19. Производитель данных и утилизатор соединения JDBC

public class JDBCConnectionProducer {

··@Produces

··private Connection createConnection() {

····Connection conn = null;

····try {

······Class.forName("org.apache.derby.jdbc.EmbeddedDriver"). newInstance();

······conn = DriverManager.getConnection("jdbc: derby: memory: chapter02DB", 

"APP", "APP");

····} catch (InstantiationException | IllegalAccessException | ClassNotFoundException) {

······e.printStackTrace();

····}

····return conn;

··}

··private void closeConnection(@Disposes Connection conn) throws SQLException {

····conn.close();

··}

}

Уничтожение может осуществляться путем сопоставления метода утилизатора, определенного тем же классом, что и метод производителя данных. Каждый метод утилизатора, сопровождаемый аннотацией @Disposes, должен иметь строго один параметр такого же типа (тут java.sql.Connection) и квалификаторы (@Default), как соответствующий тип возврата метода производителя данных (с аннотацией @Produces). Метод утилизатора (closeConnection()) вызывается автоматически по окончании контекста клиента (в листинге 2.20 — контекст @ApplicationScoped), и параметр получает объект, порожденный методом производителя данных.

Листинг 2.20. Производитель данных и утилизатор соединения JDBS

@ApplicationScoped

public class DerbyPingService {

··@Inject

··private Connection conn;

··public void ping() throws SQLException {

····conn.createStatement(). executeQuery("SELECT 1 FROM SYSIBM.SYSDUMMY1");

··}

}

Листинг 2.20 показывает, как компонент внедряет созданное соединение JDBC с аннотацией @Inject и использует его для проверки доступности базы данных Derby. Как видите, этот клиентский код не занимается всеми вспомогательными задачами по созданию и закрытию соединения JDBC либо обработке исключений. Производители данных и утилизаторы — хороший способ создания и закрытия ресурсов.

Области видимости

CDI имеет отношение не только к внедрению зависимостей, но и к контексту (буква С в аббревиатуре CDI означает контекст). Каждый объект, управляемый CDI, имеет строго определенные область видимости и жизненный цикл, которые связаны с конкретным контекстом. В Java область применения POJO достаточно проста: вы создаете экземпляр класса, используя ключевое слово new, и позволяете сборщику мусора избавиться от него, чтобы освободить некоторое количество памяти. При использовании CDI компонент связан с контекстом и остается в нем до тех пор, пока не будет разрушен контейнером. Удалить компонент из контекста вручную невозможно.

В то время как веб-уровень имеет четко определенные области видимости (приложение, сеанс, запрос), на уровне сервисов такого не было (см. также главу 7 о компонент-сеансах EJB с сохранением и без сохранения состояния). Ведь, когда компонент-сеансы или POJO используются в веб-приложениях, они не оповещаются о контекстах этих приложений. CDI соединил веб-уровень с уровнем сервисов с помощью содержательных областей видимости. Он определяет следующие встроенные области видимости и даже предлагает точки расширения, в которых вы можете создавать собственные области видимости.

• Область видимости приложения (@ApplicationScoped) — действует на протяжении всей работы приложения. Компонент создается только один раз на все время работы приложения и сбрасывается, когда оно закрывается. Эта область видимости полезна для утилитных или вспомогательных классов либо объектов, которые хранят данные, используемые совместно целым приложением. Однако необходимо проявить осторожность в вопросах конкурентного доступа, когда доступ к данным должен осуществляться по нескольким потокам.

• Область видимости сеанса (@SessionScoped) — действует на протяжении нескольких запросов HTTP или нескольких вызовов метода для одного пользовательского сеанса. Компонент создается на все время длительности HTTP-сеанса и сбрасывается, когда сеанс заканчивается. Эта область видимости предназначена для объектов, требуемых на протяжении сеанса, таких как пользовательские настройки или данные для входа в систему.

• Область видимости запроса (@RequestScoped) — соответствует единственному HTTP-запросу или вызову метода. Компонент создается на все время вызова метода и сбрасывается по его окончании. Он используется для классов обслуживания или связующих компонентов JSF, которые нужны только на протяжении HTTP-запроса.

• Область видимости диалога (@ConverationScoped) — действительна между множественными вызовами в рамках одной сессии, ее начальная и конечная точка определяются приложением. Диалоги используются среди множественных страниц как часть многоступенчатого рабочего потока.