blob: aaada557725913fb50b380f58c0581f686f44072 [file] [log] [blame]
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
= Aplicando Anotações de Ciclo de Vida e de Beans @Alternative
:jbake-type: tutorial
:jbake-tags: tutorials
:jbake-status: published
:icons: font
:syntax: true
:source-highlighter: pygments
:toc: left
:toc-title:
:description: Aplicando Anotações de Ciclo de Vida e de Beans @Alternative - Apache NetBeans
:keywords: Apache NetBeans, Tutorials, Aplicando Anotações de Ciclo de Vida e de Beans @Alternative
_Contribuição de Andy Gibson_
== Injeção de Dependência e Contextos
1. link:cdi-intro.html[+Introdução ao CDI e ao JSF 2.0+]
2. link:cdi-inject.html[+Trabalhando com Injeção e Qualificadores no CDI+]
3. *Aplicando Anotações @Alternative Beans e de Ciclo de Vida*
* <<alternative,Tratando Várias Implantações>>
* <<lifecycle,Aplicando Anotações de Ciclo de Vida em Beans gerenciado>>
* <<seealso,Consulte Também>>
. link:cdi-events.html[+Trabalhando com Eventos no CDI+]
A Injeção de Dependência e Contextos (CDI), especificada por link:http://jcp.org/en/jsr/detail?id=299[+JSR-299+], é parte integrante do Java EE 6 e fornece uma arquitetura que permite aos componentes do Java EE, como os servlets, enterprise beans e JavaBeans, existirem dentro do ciclo de vida de uma aplicação com escopos bem definidos. Além disso, os serviços CDI permitem que os componentes do Java EE, como beans de sessão EJB e beans gerenciados do JavaServer Faces (JSF), sejam injetados e interajam de maneira acoplada flexível, disparando e observando eventos.
Este tutorial tem base no post do blog de Andy Gibson, intitulado link:http://www.andygibson.net/blog/index.php/2009/12/22/getting-started-with-cdi-part-2-injection/[+Introdução ao CDI parte 2: Injeção+]. Ele demonstra como é possível usufruir da anotação `@Alternative` para configurar sua aplicação para diferentes implantações e também como utilizar as anotações do ciclo de vida do bean gerenciado, como a `@PostConstruct`e a `@PostDestroy`, para combinar a injeção CDI com a funcionalidade fornecida pela link:http://jcp.org/en/jsr/detail?id=316[+Especificação do Bean Gerenciado do Java EE 6+].
O NetBeans IDE fornece um suporte incorporado para a Injeção de Dependência e Contextos, incluindo a opção de geração do arquivo de configuração de CDI `beans.xml` durante a criação do projeto, do editor e do suporte de navegação para anotações, assim como vários assistentes para a criação de artefatos CDI comumente utilizados.
Para concluir este tutorial, você precisa dos seguintes recursos e softwares.
|===
|Software ou Recurso |Versão Necessária
|link:https://netbeans.org/downloads/index.html[+NetBeans IDE+] |Versão Java EE 7.2, 7.3, 7.4, 8.0
|link:http://www.oracle.com/technetwork/java/javase/downloads/index.html[+JDK (Java Development Kit)+] |versão 7 ou 8
|link:http://glassfish.dev.java.net/[+GlassFish Server+] |Open Source Edition 3.x ou 4.x
|link:https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252FcdiDemo2.zip[+cdiDemo2.zip+] |n/d
|===
[NOTE]
====
* O pacote Java EE do NetBeans inclui também o GlassFish Server Open Source Edition, que é um contêiner compatível com Java EE.
* É possível fazer download do projeto modelo de solução deste tutorial: link:https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252FcdiDemo3.zip[+cdiDemo3.zip+]
====
[[alternative]]
== Tratando Várias Implantações
O CDI oferece o uso da anotação `@Aternative` que lhe permite encapsular vários beans que coincidem com um ponto de injeção sem erros de ambiguidade. Em outras palavras, é possível aplicar a anotação `@Alternative` a dois ou mais beans e, em seguida, com base na implantação, especificar o bean que deseja utilizar no arquivo de configuração do CDI `beans.xml`.
Considere o seguinte cenário como demonstração disso. Nós injetamos um `ItemValidator` na nossa classe `ItemProcessor` principal. O `ItemValidator` é implementado pelo `DefaultItemValidator` e pelo `RelaxedItemValidator`. Com base nos requisitos de implantação, gostaríamos de utilizar o `DefaultItemValidator` para a maior parte dos casos, mas também é exigido o `RelaxedItemValidator` para uma implantação específica. Para resolver isso, anotamos os dois beans e, em seguida, especificamos qual bean utilizar para uma determinada implantação, adicionando uma entrada ao arquivo `beans.xml` da aplicação.
image::images/cdi-diagram-alternative.png[title="Use a injeção de CDI para acoplar, livremente, as classes na sua aplicação"]
1. Começando pela extração do projeto inicial modelo a partir do arquivo `cdiDemo2.zip` (Consulte a <<requiredSoftware,tabela acima, que lista os recursos necessários>>.) Abra o projeto no IDE escolhendo Arquivo > Abrir Projeto (Ctrl-Shift-O; ⌘-Shift-O no Mac) e, em seguida, selecionando o projeto no seu local no computador.
2. Clique com o botão direito do mouse no nó do projeto na janela Projetos e escolha Propriedades.
3. Selecione a categoria Executar e confirme se a instância do GlassFish está selecionada na lista drop-down Servidor.
4. Crie uma interface `ItemValidator`.
Clique no botão Novo Arquivo (image:images/new-file-btn.png[]) ou pressione CTRL-N (⌘-N no Mac) para abrir o assistente de Arquivo.
. Selecione a categoria Java e, em seguida, selecione Interface Java. Clique em Próximo.
. Digite *ItemValidator* como o nome da classe e, em seguida, *exercício3* como o pacote.
. Clique em Finalizar. A nova interface será gerada e aberta no editor.
. Adicione um método chamado `isValid()` que utiliza um objeto `Item` e retorna um valor `boolean`.
[source,java]
----
public interface ItemValidator {
*boolean isValid(Item item);*
}
----
(Utilize a dica do editor para adicionar a instrução de importação para o `exercise2.Item`.)
. Expanda a classe `ItemProcessor` para incorporar a nova funcionalidade. Abra o `ItemProcessor` no editor e faça as seguintes alterações.
[source,java]
----
@Named
@RequestScoped
public class ItemProcessor {
@Inject @Demo
private ItemDao itemDao;
*@Inject
private ItemValidator itemValidator;*
public void execute() {
List<Item> items = itemDao.fetchItems();
for (Item item : items) {
System.out.println(*"Item = " + item + " valid = " + itemValidator.isValid(item)*);
}
}
}
----
(Utilize a dica do editor para adicionar a instrução de importação para `exercise3.ItemValidator`.)
. Crie uma implementação do `ItemValidator` chamado `DefaultItemValidator` que simplesmente testa o limite com relação ao valor.
Na janela Projetos, clique com o botão direito do mouse no pacote `exercise3` e selecione Nova > Classe Java. Nomeie a classe como *DefaultItemValidator* e clique em Finalizar.
. Faça com que o `DefaultItemValidator` implemente o `ItemValidator` e substitua o método `isValid()` como se segue.
[source,java]
----
public class DefaultItemValidator *implements ItemValidator* {
*@Override
public boolean isValid(Item item) {
return item.getValue() < item.getLimit();
}*
}
----
(Utilize a dica do editor para adicionar a instrução de importação para o `exercise2.Item`.)
. Clique no botão Executar Projeto (image:images/run-project-btn.png[]) na barra de ferramentas principal do IDE. O projeto é compilado e implantado no GlassFish e a página de boas-vindas da aplicação (`process.xhtml`) será aberta no browser.
. Clique no botão "`Execute`" que é exibido na página. Volte ao IDE e examine o log do GlassFish Server. O log do servidor é exibido na janela Saída (Ctrl-4; ⌘-4 no Mac) na guia GlassFish. É possível notar que os itens estão sendo validados e que o único item válido listado é o caso em que o valoe é menor que o limite.
[source,java]
----
INFO: Item = exercise2.Item@e857ac [Value=34, Limit=7] valid = false
INFO: Item = exercise2.Item@63124f52 [Value=4, Limit=37] valid = true
INFO: Item = exercise2.Item@4715c34e [Value=24, Limit=19] valid = false
INFO: Item = exercise2.Item@65c95a57 [Value=89, Limit=32] valid = false
----
image::images/output-window.png[title="Exiba o log do servidor na janela Saída"]
. Agora, considere o cenário onde temos que implantar em um site diferente, mais flexível, e considere um item como inválido somente se o valor for mais de duas vezes maior que o limite. Pode ser necessário ter um outro bean que implemente a interface `ItemValidator` para essa lógica.
Crie uma nova implementação do `ItemValidator` chamada `RelaxedItemValidator`. Na janela Projetos, clique com o botão direito do mouse no pacote `exercise3` e selecione Nova > Classe Java. Nomeie a classe *RelaxedItemValidator* e clique em Finalizar.
. Faça com que o `RelaxedItemValidator` implemente o `ItemValidator` e substitua o método `isValid()` como se segue.
[source,java]
----
public class RelaxedItemValidator *implements ItemValidator* {
*@Override
public boolean isValid(Item item) {
return item.getValue() < (item.getLimit() * 2);
}*
}
----
(Utilize a dica do editor para adicionar a instrução de importação para o `exercise2.Item`.)
. Clique no botão Executar Projeto (image:images/run-project-btn.png[]) para executar o projeto. Observe que o projeto agora falha na implantação.
. Examine o log do servidor na janela Saída (Ctrl-4; ⌘-4 no Mac). Você nota uma mensagem de erro relatando um problema de "dependência ambígua". Isso ocorre porque agora temos duas classes implementando a mesma interface.
[source,java]
----
org.glassfish.deployment.common.DeploymentException: Injection point has ambiguous dependencies.
Injection point: field exercise2.ItemProcessor.itemValidator;
Qualifiers: [@javax.enterprise.inject.Default()];
Possible dependencies: [exercise3.RelaxedItemValidator, exercise3.DefaultItemValidator]
----
Weld, a implementação para CDI, não pode determinar se deve utilizar o `RelaxedItemValidator` ou o `DefaultItemValidator` para o ponto de injeção fornecido.
Como mencionado anteriormente, a única diferença é baseada na implantação. Para a maioria das implantações, preferimos utilizar o validador default, mas para uma implantação, preferimos utilizar a implantação "flexível". O CDI oferece o uso da anotação `@Alternative` que lhe permite encapsular vários beans que coincidam com um ponto de injeção sem erros de ambiguidade e o bean a ser utilizado, que é definido no arquivo `beans.xml`. Isso lhe permite implantar as duas implementações no mesmo módulo com a definição `beans.xml` sendo a única diferença, que pode ser alterada ao longo de implantações diferentes.
. Adicione a anotação `@Alternative` e as instruções de importação correspondentes a `RelaxedItemValidator` e `DefaultItemValidator`.
Abra o `RelaxedItemValidator` no editor e faça as seguintes alterações.
[source,java]
----
*import javax.enterprise.inject.Alternative;*
...
*@Alternative*
public class RelaxedItemValidator implements ItemValidator {
public boolean isValid(Item item) {
return item.getValue() < (item.getLimit() * 2);
}
}
----
Digite "`@Al`" e, em seguida, pressione Ctrl-Espaço para chamar a funcionalidade autocompletar código. Como somente uma opção é filtrada, a anotação `@Alternative` é autocompletada e a instrução de importação correspondente para o `javax.enterprise.inject.Alternative` é adicionada automaticamente à parte superior do arquivo. Normalmente, ao pressionar Ctrl-Espaço nas anotações também é fornecido uma documentação pop-up Javadoc.
image::images/code-completion-alternative.png[title="Pressione Ctrl-Espaço em anotações para chamar a documentação Javadoc"]
Alterne para `DefaultItemValidator` (pressione Ctrl-Tab) e faça as alterações a seguir.
[source,java]
----
*import javax.enterprise.inject.Alternative;*
...
*@Alternative*
public class DefaultItemValidator implements ItemValidator {
public boolean isValid(Item item) {
return item.getValue() < item.getLimit();
}
}
----
Se tivéssemos implantado a aplicação, agora obteríamos uma mensagem de erro "dependência não-satisfeita", já que definimos os dois beans coincidentes como alternativos, mas não ativamos nenhum deles no arquivo `beans.xml`.
. Utilize a caixa de diálogo Ir para Arquivo do IDE para abrir rapidamente o arquivo `beans.xml`. Selecione Navegar > Ir para Arquivo no menu principal do IDE (Alt-Shift-O; Ctrl-Shift-O no Mac) e, em seguida, digite "`beans`". Clique em OK.
image::images/go-to-file.png[title="Use a caixa de diálogo Ir para Arquivo para localizar rapidamente um arquivo de projeto"]
. Faça as seguintes alterações no arquivo `bean.xml`.
[source,xml]
----
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
*<alternatives>
<class>exercise3.RelaxedItemValidator</class>
</alternatives>*
</beans>
----
Isso informa ao CDI que o `RelaxedItemValidator` deve ser usado para esta implantação. É possível achar que a anotação `@Alternative` desativa efetivamente o bean, tornando-o indisponível para injeção, mas permitindo que a implementação seja encapsulada com os outros beans. Adicioná-la como uma alternativa no arquivo `beans.xml` reabilita efetivamente o bean, tornando-o disponível para injeção. Ao movermos esse tipo de metadados para o arquivo `beans.xml`, podemos colocar no pacote versões diferentes do arquivo à várias implantações.
. Clique no botão Executar Projeto (image:images/run-project-btn.png[]) para executar o projeto (como alternativa, Pressione F6; fn-F6 no Mac). No browser, clique no botão "`Execute`" exibido na página. Volte ao IDE e examine o log do GlassFish Server exibido na janela Saída (Ctrl-4; ⌘-4 no Mac).
[source,java]
----
INFO: Item = exercise2.Item@672f0924 [Value=34, Limit=7] valid = false
INFO: Item = exercise2.Item@41014f68 [Value=4, Limit=37] valid = true
INFO: Item = exercise2.Item@3d04562f [Value=24, Limit=19] valid = true
INFO: Item = exercise2.Item@67b646f4 [Value=89, Limit=32] valid = false
----
Você pode notar que a implementação `RelaxedItemValidator` está sendo utilizada como o terceiro item exibido como válido, ao mesmo tempo em que o valor fornecido (`24`) é maior que o limite informado (`19`).
[[lifecycle]]
== Aplicando Anotações de Ciclo de Vida aos Beans Gerenciados
Neste exercício, será injetado um `ItemErrorHandler` na `ItemProcessor` principal. Como o `FileErrorReporter` é a única implementação da interface `ItemErrorHandler`, ela será selecionada como a injeção. Para configurar as ações específicas de ciclo de vida para a classe, é necessário utilizar as anotações `@PostConstruct` e `@PreDestroy` a partir da especificação do Bean gerenciado (incluídas no link:http://jcp.org/en/jsr/detail?id=316[+JSR 316: Plataforma Java, Especificação do Enterprise Edition 6+]).
image::images/cdi-diagram-lifecycle.png[title="Use a injeção de CDI para acoplar, livremente, as classes na sua aplicação"]
Prosseguindo com o exemplo, crie uma interface `ItemErrorHandler` para tratar itens inválidos ao serem descobertos.
1. Na janela Projetos, clique com o botão direito do mouse no pacote `exercise3` e selecione Nova > Interface Java.
2. No assistente de Interface Java, digite *ItemErrorHandler* como o nome da classe e, em seguida *exercício3* como o pacote. Clique em Finalizar.
A nova interface será gerada e aberta no editor.
. Adicione o método chamado `handleItem()` que utiliza um objeto `Item` como um argumento.
[source,java]
----
public interface ItemErrorHandler {
*void handleItem(Item item);*
}
----
(Utilize a dica do editor para adicionar a instrução de importação para o `exercise2.Item`.)
. Comece com a implementação do `ItemErrorHandler` com um handler falso chamado `FileErrorReporter` que salva os detalhes do item em um arquivo.
Na janela Projetos, clique com o botão direito do mouse no pacote `exercise3` e selecione Nova > Classe Java. Nomeie a classe *FileErrorReporter* e clique em Finalizar.
. Faça com que o `FileErrorReporter` implemente o `ItemErrorHandler` e substitua o método `handlerItem()` como se segue.
[source,java]
----
public class FileErrorReporter *implements ItemErrorHandler* {
*@Override
public void handleItem(Item item) {
System.out.println("Saving " + item + " to file");
}*
}
----
(Utilize a dica do editor para adicionar a instrução de importação para o `exercise2.Item`.)
Você deseja abrir o arquivo antes de começar a tratar itens, portanto, deixe-o aberto durante o processo em que o conteúdo é adicionado ao arquivo e, em seguida, feche o arquivo quando processamento tiver sido concluído. Você poderia adicionar manualmente os métodos `initProcess()` e `finishProcess()` ao bean de informe de erro, mas então não poderia codificar a interface, já que o chamador precisaria conhecer esses métodos específicos da classe. Você poderia adicionar esses mesmos métodos à interface `ItemErrorReporter`, mas então seria necessário implementar desnecessariamente tais métodos em cada classe que implemente aquela interface. Em vez disso, é possível utilizar algumas das anotações de ciclo de vida da especificação do Bean Gerenciado (incluídas na link:http://jcp.org/en/jsr/detail?id=316[+JSR 316: plataforma Java, Especificação do Enterprise Edition 6+]) para chamar os métodos no bean em alguns pontos no ciclo de vida do bean. Um método anotado `@PostConstruct` é chamado quando o bean tiver sido construído e qualquer dependência do bean tiver sido injetada. Da mesma forma, um método anotado `@PreDestroy` é chamado um pouco antes do bean ser descartado pelo contêiner.
. Adicione os seguintes métodos `init()` e `release()` com as anotações `@PostConstruct` e `@PreDestroy` correspondentes.
[source,java]
----
public class FileErrorReporter implements ItemErrorHandler {
*@PostConstruct
public void init() {
System.out.println("Creating file error reporter");
}
@PreDestroy
public void release() {
System.out.println("Closing file error reporter");
}*
@Override
public void handleItem(Item item) {
System.out.println("Saving " + item + " to file");
}
}
----
. Corrigir importações. Clique com o botão direito do mouse no editor e selecione Corrigir importações ou pressione Ctrl-Shift-I (⌘-Shift-I no Mac). Instruções de importação para `javax.annotation.PostConstruct` e `javax.annotation.PreDestroy` serão adicionadas à parte superior do arquivo.
. Finalmente, adicione o novo bean `ItemErrorHandler` ao `ItemProcessor`.
[source,java]
----
@Named
@RequestScoped
public class ItemProcessor {
@Inject @Demo
private ItemDao itemDao;
@Inject
private ItemValidator itemValidator;
*@Inject
private ItemErrorHandler itemErrorHandler;*
public void execute() {
List<Item> items = itemDao.fetchItems();
for (Item item : items) {
*if (!itemValidator.isValid(item)) {
itemErrorHandler.handleItem(item);
}*
}
}
}
----
(Utilize a dica do editor para adicionar a instrução de importação para o `exercise3.ItemErrorHandler`.)
. Clique no botão Executar Projeto (image:images/run-project-btn.png[]) para executar o projeto (como alternativa, Pressione F6; fn-F6 no Mac). No browser, clique no botão "`Execute`" exibido na página. Volte ao IDE e examine o log do GlassFish Server exibido na janela Saída (Ctrl-4; ⌘-4 no Mac).
[source,java]
----
INFO: Creating file error reporter
INFO: Saving exercise2.Item@6257d812 [Value=34, Limit=7] to file
INFO: Saving exercise2.Item@752ab82e [Value=89, Limit=32] to file
INFO: Closing file error reporter
----
link:/about/contact_form.html?to=3&subject=Feedback:%20Using%20CDI%20Injection%20to%20Perform%20Custom%20Validation[+Enviar Feedback neste Tutorial+]
[[seealso]]
== Consulte Também
Diferentes implantações de aplicações podem utilizar regras diversas para tratar itens inválidos, tal como a rejeição de um item, o envio de notificações aos indivíduos, a sinalização desses itens, ou simplesmente a listagem deles em um arquivo de saída. Além disso, é possível fazer uma combinação dessas regras (ex., rejeitar um pedido, enviar um e-mail a um representante de vendas e listar o pedido em um arquivo). Uma maneira excelente de tratar esse tipo de problema multifacetado é utilizando _eventos_. Os eventos CDI são o assunto do artigo final desta série:
* link:cdi-events.html[+Trabalhando com Eventos no CDI+]
Para obter mais informações sobre o CDI e o Java EE, consulte os recursos a seguir.
* link:cdi-intro.html[+Introdução à Injeção de Dependência e Contextos e JSF 2.0+]
* link:cdi-inject.html[+Trabalhando com Injeção e Qualificadores no CDI+]
* link:javaee-gettingstarted.html[+Conceitos Básicos sobre Aplicações do Java EE+]
* link:http://blogs.oracle.com/enterprisetechtips/entry/using_cdi_and_dependency_injection[+Dica Técnica do Enterprise: Utilizando Injeção de Dependência e de CDI para Java em uma Aplicação JSF 2.0+]
* link:http://download.oracle.com/javaee/6/tutorial/doc/gjbnr.html[+O Tutorial do Java EE 6, Parte V: Injeção de Dependência e Contextos para a Plataforma Java EE+]
* link:http://jcp.org/en/jsr/detail?id=299[+JSR 299: Especificação para Injeção de Dependência e Contextos+]
* link:http://jcp.org/en/jsr/detail?id=316[+JSR 316: Plataforma Java, Especificação do Enterprise Edition 6+]