CDI стал общим основанием для нескольких спецификаций Java EE. Одни спецификации в большой степени полагаются на него (Bean Validation, JAX-RS), другие посодействовали его возникновению (EJB), а третьи связаны с ним (JSF). CDI 1.1 затрагивает несколько спецификаций, но является неполным без остальных: Dependency Injection for Java 1.0 (запрос JSR 330), Managed Bean 1.0 (запрос JSR 342), Common Annotations 1.2 (запрос JSR 250), Expression Language 3.0 (запрос JSR 341) и Interceptors 1.2 (запрос JSR 318).
Краткая история спецификаций CDI
В 2006 году Гевин Кинг (создатель Seam), вдохновленный идеями фреймворков Seam, Guise и Spring, возглавил работу над спецификацией по запросу JSR 299, позднее названной Web Beans (Веб-компоненты). Поскольку она создавалась для Java EE 6, ее пришлось переименовать в Context and Dependency Injection 1.0. При этом за основу был взят новый запрос JSR 330: Dependency Injection for Java 1.0 (также известный как @Inject).
Эти две спецификации взаимно дополняли друг друга и не могли использоваться в Java EE по отдельности. Внедрение зависимостей для Java определяло набор аннотаций (@Inject, @Named, @Qualifier, @Scope и @Singleton), используемых преимущественно для внедрения. CDI дал семантику запросу JSR 330 и добавил еще больше новых возможностей, таких как управление контекстом, события, декораторы и улучшенные перехватчики (запрос JSR 318). Более того, CDI позволил разработчику расширить платформу в рамках стандарта, что ранее не представлялось возможным. Целью CDI было заполнить все пробелы, а именно:
• придать платформе большую целостность;
• соединить веб-уровень и уровень транзакций;
• сделать внедрение зависимостей полноправным компонентом платформы;
• иметь возможность легко добавлять новые расширения.
Сегодня, с появлением Java EE 7, CDI 1.1 становится основанием для многих запросов JSR, и здесь уже появились определенные улучшения.
Что нового в CDI 1.1
В CDI 1.1 не добавилось никаких важных функций. Вместо этого новая версия концентрируется на интеграции CDI с другими спецификациями, например, благодаря активному использованию перехватчиков, добавлению диалогов в запрос сервлета либо обогащению событий жизненного цикла приложения в Java EE. Ниже перечислены новые возможности, реализованные в CDI 1.1:
• новый класс CDI обеспечивает программный доступ к средствам CDI извне управляемого компонента;
• перехватчики, декораторы и альтернативы могут быть приоритизированы (@Priority) и упорядочены для всего приложения;
• при добавлении аннотации @Vetoed к любому типу или пакету CDI перестает считать данный тип или пакет своим компонентом;
• квалификатор @New в CDI 1.1 считается устаревшим, и сегодня приложениям предлагается вместо этого внедрять ограниченные компоненты @Dependent;
• новая аннотация @WithAnnotations позволяет расширению фильтровать, какие типы оно будет видеть.
В табл. 2.1 перечисляются основные пакеты, относящиеся к CDI. Вы найдете аннотации и классы CDI в пакетах javax.enterprise.inject и javax.decorator.
Пакет | Описание |
---|---|
javax.inject | Содержит базовую спецификацию по внедрению зависимостей для Java API (запрос JSR 330) |
javax.enterprise.inject | Основные API для внедрения зависимостей |
javax.enterprise.context | Области видимости CDI и контекстуальные API |
javax.enterprise.event | События CDI и API алгоритмов наблюдения |
javax.enterprise.util | Пакет утилит CDI |
javax.interceptor | Содержит API перехватчика (запрос JSR 318) |
javax.decorator | API декоратора CDI |
Базовая реализация
Базовой реализацией CDI является Weld, свободный проект от JBoss. Есть и другие реализации, такие как Apache OpenWebBeans или CanDi (от Caucho). Важно также упомянуть проект Apache DeltaSpike, который ссылается на набор портируемых расширений CDI.
Создание компонента CDI
Компонентом CDI может быть тип любого класса, содержащий бизнес-логику. Он может вызываться напрямую из Java-кода посредством внедрения либо с помощью языка выражений (EL) со страницы JSF. Как показано в листинге 2.1, компонент — это объект POJO, который не наследует от других объектов и не расширяет их, может внедрять ссылки на другие компоненты (@Inject) и имеет свой жизненный цикл, управляемый контейнером (@PostConstruct). Вызовы метода, выполняемые таким компонентом, могут перехватываться (здесь @Transactional основана на перехватчике и далее описана подробнее).