Desde o seu lançamento em 2009, Context and Dependency Injection (CDI) vem se tornando uma das tecnologias mais importantes da plataforma Java EE. Após mais de dois anos de trabalho desde a versão 1.2, a especificação final de CDI 2.0 foi publicada em abril de 2017. Ao mesmo tempo, sua implementação de referência, Weld 3.0, também foi disponibilizada para uso.
Nessa versão, provavelmente a funcionalidade mais notável é o recém-adicionado suporte a Java SE. Sempre houve uma grande demanda para utilizar injeção de dependências em outros ambientes, sejam frameworks web alternativos ou aplicações desktop. Buscando atender a esta necessidade, essa especificação traz novas APIs que permitem inicializar um container CDI manualmente.
Para melhor incorporar as funcionalidades de Java SE, o próprio documento foi reestruturado. A nova versão da especificação está dividida em três partes. A primeira especifica o núcleo de CDI: injeção de dependências, contextos, eventos, decoradores, interceptadores etc. Este conteúdo é aplicável tanto a Java SE quanto a Java EE. É a primeira parte que contém a maior parte do documento, inclusive o conteúdo mais antigo. Ainda assim, ela traz algumas novidades interessantes, como novas SPIs (especialmente interessantes para desenvolvedores de frameworks), ordenação de observadores de eventos, eventos assíncronos, configurators para métodos observadores e algumas facilidades de Java 8.
Por sua vez, a segunda parte da especificação descreve a API para utilizar CDI em Java SE. Aqui, o conteúdo mais relevante é a explicação de como iniciar um container CDI em uma aplicação standalone. Veremos como isto é feito mais à frente.
Por fim, referências a outras especificações Java EE ou a comportamentos específicos de servidores foram extraídas para a terceira parte. Nela, especifica-se como CDI interage com tecnologias como EJBs e Expression Language (EL). No geral, há poucas novidades neste aspecto: o conteúdo desta parte já pode ser encontrado em sua quase totalidade nas versões anteriores de CDI.
Neste artigo, exploraremos as novidades de aplicação mais generalizada. Veremos primeiro como ordenar observadores de eventos, uma feature muito útil para evitar race conditions e outros problemas similares. Posteriormente conheceremos os poderosos eventos assíncronos. Programação assíncrona é uma tendência, dado o seu poder e performance; com eventos assíncronos, podemos utilizar este estilo de desenvolvimento de maneira bastante intuitiva. Naturalmente, o uso de CDI em Java SE não passará em branco: há uma seção inteira dedicada a entender como utilizar essa excitante novidade. O novo CDI traz também alguns literais de anotações predefinidos que merecem uma breve análise. Por fim, há exemplos de como as novas capacidades de Java 8 (lambdas, streams) foram utilizadas na especificação.
Interessado? Comecemos então por uma funcionalidade há muito solicitada pela comunidade: previsibilidade na ordem de execução de observadores de eventos.
Ordenação de observadores de eventos
Desde CDI 1.1, decoradores e interceptadores podem ser ordenados. Basicamente, podemos definir que um interceptador (ou decorador) será chamado antes de outro através da anotação @Priority. Desde então, a comunidade vinha pedindo uma maneira de definir também a ordem de execução dos observadores de um evento. A nova especificação finalmente nos permite fazer isso.
Ordenando eventos
Idealmente, observadores de eventos devem ser os mais independentes possível: um observer não deveria afetar o resultado de outro executado posteriormente. Isto mantém o código desacoplado e fácil de compreender.
Isto não é sempre possível, porém, e até CDI 1.2, nada poderia ser feito a esse respeito. CDI 2.0 finalmente traz uma solução: podemos utilizar a anotação @javax.annotation.Priority para ordenar observers em relação a outros. Esta anotação deve ser adicionada ao argumento com @Observes e exige um parâmetro, do tipo int, que é a prioridade de execução.
Na Listagem 1 temos um exemplo de método observer com prioridade. Note que o argumento objeto do método possui duas anotações. @Observes declara este método como observador, enquanto @Priority(1) define a prioridade de execução.
Listagem 1. Declarando um observador com prioridade.
public class ExemploObserver {
public void metodo(@Observes @Priority(1) Object objeto) {
System.err.println("Exemplo de observador com prioridade.");
}
}
Observadores com prioridade menor são executados antes de outros com prioridades maiores. Assim, por exemplo, o método da Listagem 2 será necessariamente executado depois do observador da Listagem 1.
Listagem 2. Um observador menos prioritário.
public class ExemploObserverMenosPrioritario {
public void outroMetodo(@Observes @Priority(2) Object objeto) {
System.err.println("Este observer será executado posteriormente.");
}
}
Como se vê, o processo para definir a prioridade do observador é bem simples. Ao ordenar observadores, o maior desafio está em decidir que valores de prioridades utilizar.
Definindo prioridades
Embora @Priority aceite qualquer inteiro não-negativo, é importante escolher bem os valores das prioridades.
Considere, por exemplo, prioridades pequenas, como 0 ou 1. Estas prioridades devem ser raramente utilizadas, pois nos impedem de executar observadores antes dos já definidos. De modo similar, se utilizarmos valores muito próximos (digamos, 1000 e 1001), não será possível executar um observador entre os dois. De qualquer forma, se utilizarmos prioridades arbitrárias, podem ocorrer conflitos com observadores definidos pela plataforma, ou por bibliotecas.
Felizmente, a plataforma provê uma maneira mais portável de definir os valores de prioridades. A classe interna javax.interceptor.Interceptor.Priority define algumas constantes que nos ajudam a escolher estes valores de maneira mais consistente. Os valores destas constantes são definidos de acordo com os seguintes princípios:
- A JVM e os servidores de aplicação – enfim, a plataforma – devem ser capazes de executar observadores antes que qualquer outro código (para garantir um estado consistente) e depois que todos os outros foram executados (para liberarem recursos);
- Bibliotecas precisam executar observadores antes da aplicação (de modo a ficarem em estado consistente para serem usadas), assim como depois da aplicação (para desalocarem quaisquer recursos que consumam);
- Os observadores definidos pela aplicação,
portanto, devem ...
Quer ler esse conteúdo completo? Tenha acesso completo
Confira outros conteúdos:
Por Adam Em 2018Black November
Desconto exclusivo para as primeiras 200 matrículas!
Pagamento anual
12x no cartão
De: R$ 69,00
Por: R$ 59,00
Total: R$ 708,00
Garanta o desconto
- Formação FullStack Completa
- Carreira Front-end I e II, Algoritmo e Javascript, Back-end e Mobile
- +10.000 exercícios gamificados
- +50 projetos reais
- Comunidade com + 200 mil alunos
- Estude pelo Aplicativo (Android e iOS)
- Suporte online
- 12 meses de acesso
Pagamento recorrente
Cobrado mensalmente no cartão
De: R$ 79,00
Por: R$ 64,00 /mês
Total: R$ 768,00
Garanta o desconto
- Formação FullStack Completa
- Carreira Front-end I e II, Algoritmo e Javascript, Back-end e Mobile
- +10.000 exercícios gamificados
- +50 projetos reais
- Comunidade com + 200 mil alunos
- Estude pelo Aplicativo (Android e iOS)
- Suporte online
- Fidelidade de 12 meses
- Não compromete o limite do seu cartão
<Perguntas frequentes>
Nossos casos de sucesso
Eu sabia pouquíssimas coisas de programação antes de começar a estudar com vocês, fui me especializando em várias áreas e ferramentas que tinham na plataforma, e com essa bagagem consegui um estágio logo no início do meu primeiro período na faculdade.
Estudo aqui na Dev desde o meio do ano passado! Nesse período a Dev me ajudou a crescer muito aqui no trampo.
Fui o primeiro desenvolvedor contratado pela minha empresa. Hoje eu lidero um time de desenvolvimento!
Minha meta é continuar estudando e praticando para ser um Full-Stack Dev!Economizei 3 meses para assinar a plataforma e sendo sincero valeu muito a pena, pois a plataforma é bem intuitiva e muuuuito didática a metodologia de ensino. Sinto que estou EVOLUINDO a cada dia. Muito obrigado!
Nossa! Plataforma maravilhosa. To amando o curso de desenvolvimento front-end, tinha coisas que eu ainda não tinha visto. A didática é do jeito que qualquer pessoa consegue aprender. Sério, to apaixonado, adorando demais.
Adquiri o curso de vocês e logo percebi que são os melhores do Brasil. É um passo a passo incrível. Só não aprende quem não quer. Foi o melhor investimento da minha vida!
Foi um dos melhores investimentos que já fiz na vida e tenho aprendido bastante com a plataforma. Vocês estão fazendo parte da minha jornada nesse mundo da programação, irei assinar meu contrato como programador graças a plataforma.
Wanderson Oliveira
Comprei a assinatura tem uma semana, aprendi mais do que 4 meses estudando outros cursos. Exercícios práticos que não tem como não aprender, estão de parabéns!
Obrigado DevMedia, nunca presenciei uma plataforma de ensino tão presente na vida acadêmica de seus alunos, parabéns!
Eduardo Dorneles
Aprendi React na plataforma da DevMedia há cerca de 1 ano e meio... Hoje estou há 1 ano empregado trabalhando 100% com React!
Adauto Junior
Já fiz alguns cursos na área e nenhum é tão bom quanto o de vocês. Estou aprendendo muito, muito obrigado por existirem. Estão de parabéns... Espero um dia conseguir um emprego na área.
Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.
Aceitar