corner imagecorner image
IDEPlatformPluginsDocs & SupportCommunityPartners

Aplicação do @Alternative Beans e das Anotações do ciclo de vida

Contribuição de Andy Gibson

O conteúdo desta página se aplica ao NetBeans IDE 6.9, 7.0 e 7.1

A injeção de dependência e contextos (CDI), especificada por JSR-299, é uma parte integral do Java EE 6 e fornece uma arquitetura que permite que os componentes Java EE, como os servlets, enterprise beans e JavaBeans, existam dentro do ciclo de vida de um aplicativo com escopos bem definidos. Além disso, os serviços CDI permitem que os componentes Java EE, tais como beans de sessão EJB e os beans gerenciados do JavaServer Faces (JSF), sejam injetados e interajam de uma maneira acoplada flexível com o disparo e a observação de eventos.

Este tutorial tem base no blog de Andy Gibson, intitulado Primeiros passos com o CDI parte 2: injeção. Ele demonstra como é possível usufruir da anotação @Alternative para configurar seu aplicativo para diferentes implementações e também como utilizar as anotações do ciclo de vida do bean gerenciado, tal como a @PostConstructe a @PostDestroy, para combinar a injeção CDI com a funcionalidade fornecida pela especificação do Bean gerenciado do Java EE 6.

O NetBeans IDE fornece um suporte embutido para a Injeção de dependência e contextos, incluindo a opção de geração do arquivo de configuração 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, os seguintes recursos e softwares são necessários.

Software ou recurso Versão necessária
NetBeans IDE Versões 6.9, 7.0, 7.1 do Java EE
Java Development Kit (JDK) versão 6
Servidor GlassFish Edição 3.1 ou 3.0.1 do código-fonte aberto
cdiDemo2.zip n/d

Observações:

  • O pacote NetBeans IDE Java também inclui o servidor de aplicativos GlassFish 3.x edição de código-fonte aberto, que é um recipiente compatível com o Java EE 6.
  • O suporte para CDI também está disponível para o NetBeans 6.8 através do Patch 1.
  • O projeto modelo de solução para este tutorial pode ser baixado: cdiDemo3.zip

Manipulando várias implementações

O CDI oferece o uso da anotação @Aternative que lhe permite empacotar vários beans que coincidem com um ponto de injeção sem erros ambíguos. Em outras palavras, é possível aplicar a anotação @Alternative a dois ou mais beans e, em seguida, com base na implementaçã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 dentro da nossa classe principal ItemProcessor. O ItemValidator é implementado por ambos o DefaultItemValidator e RelaxedItemValidator. Com base nos requisitos de implementação, gostaríamos de utilizar o DefaultItemValidator para a maior parte dos casos, mas também é exigido o RelaxedItemValidator para uma implementação específica. Para resolver isso, anotamos ambos os beans e, em seguida, especificamos qual bean utilizar para uma dada implementação, adicionando uma entrada ao arquivo do aplicativo beans.xml.

O diagrama CDI mostrando os objetos criados neste exercício.
  1. Começando pela extração do projeto inicial modelo a partir do arquivo cdiDemo.zip (Consulte a tabela acima, listando os recursos necessários.) Abra o projeto no IDE escolhendo Arquivo > Abrir projeto (Ctrl-Shift-O; ⌘-Shift-O no Mac) e, em seguida, selecione o projeto no seu local no computador.
  2. Crie uma interface ItemValidator.

    Clique em Novo arquivo ( botão Novo arquivo ) ou pressione Crtl-N (⌘-N no Mac) para abrir o assistente Arquivo.
  3. Selecione a categoria Java e, em seguida, selecione Interface Java. Clique em Próximo.
  4. Digite ItemValidator como o nome da classe e, em seguida, insira exercício3 como o pacote.
  5. Clique em Terminar. A nova interface é gerada e aberta no editor.
  6. Adicione um método chamado isValid() que utiliza um objeto Item e retorna um valor booleano.
    public interface ItemValidator {
        boolean isValid(Item item);
    }
    (Utilize a dica do editor para adicionar a declaração de importação para o exercise2.Item.)
  7. Expanda a classe ItemProcessor para incorporar o novo recurso. Abra o ItemProcessor no editor e faça as seguintes alterações.
    @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 declaração de importação para o exercise3.ItemValidator.

  8. Crie uma implementação do ItemValidator chamado DefaultItemValidator que testa somente o limite contra o valor.

    Na janela Projetos, clique com o botão direito do mouse no pacote exercício3 e selecione Nova > Classe Java. Nomeie a classe como DefaultItemValidator e clique em Terminar.

  9. Faça com que oDefaultItemValidator implemente o ItemValidator e substitua o método isValid() como a seguir.
    public class DefaultItemValidator implements ItemValidator {
    
        @Override
        public boolean isValid(Item item) {
            return item.getValue() < item.getLimit();
        }
    }

    (Utilize a dica do editor para adicionar a declaração de importação para o exercise2.Item.)

  10. Clique no botão Executar projeto ( botão Executar projeto) na barra de ferramentas principal IDE. O projeto é compilado e implementado para o GlassFish e a página de boas vindas do aplicativo (process.xhtml) é aberta no navegador.
  11. Clique no botão "Executar" que é exibido na página. Alterne de volta para o IDE e examine o registro do servidor GlassFish. O registro do servidor é exibido na janela Saída (Ctrl-4; ⌘-4 no Mac) sob a aba GlassFish . É possível notar que os itens estão sendo validados e que o item listado é válido somente quando o valor é menor que o limite.
    INFO: Item =  [Value=34, Limit=7] valid = false
    INFO: Item =  [Value=4, Limit=37] valid = true
    INFO: Item =  [Value=24, Limit=19] valid = false
    INFO: Item =  [Value=89, Limit=32] valid = false
    Janela Saída: registro do servidor GlassFish
  12. Agora, considere o cenário onde temos que implementar um site diferente, mais flexível, e considerar um item como inválido somente se o valor for duas vezes maior que o limite. Talvez desejamos 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 no pacote exercício3 e selecione Nova > Classe Java. Nomeie a classe RelaxedItemValidator e clique em Terminar.

  13. Faça com que o RelaxedItemValidator implemente o ItemValidator e substitua o método isValid() como a seguir.
    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 declaração de importação para o exercise2.Item.)

  14. Clique no botão Executar projeto ( botão Executar projeto ) para executar o projeto. Observe que o projeto agora falha na implementação.
  15. Examine o registro do servidor na janela Saída (Ctrl-4; ⌘-4 no Mac). É possível observar uma mensagem de erro relatando um problema de "dependência ambígua". Isso ocorre porque agora temos duas classes implementando a mesma interface.
    org.glassfish.deployment.common.DeploymentException: o ponto de injeção possui dependências ambíguas.
    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 implementação. Para a maioria das implementações, preferimos utilizar o validador padrão, mas para uma implementação, preferimos utilizar a implementação "flexível". O CDI oferece o uso da anotação @Alternative que lhe permite empacotar vários beans que coincidam com um ponto de injeção sem erros ambíguos e o bean a ser utilizado, que é definido no arquivo beans.xml. Isso lhe permite implementar ambas as implementações no mesmo módulo com a definição beans.xml sendo a única diferença, que pode ser alterada ao longo de implementações diferentes.

  16. Adicione a anotação @Alternative e corresponda declarações de importação ao RelaxedItemValidator e DefaultItemValidator.

    Abra o RelaxedItemValidator no editor e faça as seguintes alterações.
    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 conclusão do código. Como somente uma opção é filtrada, a anotação @Alternative é completada e a declaraçã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 .

    Menu pop-up da documentação Javadoc no editor

    Alterne para DefaultItemValidator (pressione Ctrl-Tab) e faça as alterações a seguir.

    import javax.enterprise.inject.Alternative;
    ...
    
    @Alternative
    public class DefaultItemValidator implements ItemValidator {
    
        public boolean isValid(Item item) {
            return item.getValue() < item.getLimit();
        }
    }

    Se tivéssemos implementado o aplicativo, 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.

  17. Utilize a caixa de diálogo Vá para o arquivo do IDE para abrir rapidamente o arquivo beans.xml. Selecione Navegar > Vá para o arquivo no menu principal do IDE (Alt-Shift-O; Ctrl-Shift-O no Mac) e, em seguida, digite "beans". Clique em OK. Caixa de diálogo Vá para o arquivo
  18. Faça as seguintes alterações no arquivo bean.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 implementação. É possível achar que a anotação @Alternative desabilita efetivamente o bean, tornando-o indisponível para injeção, mas permitindo que a implementação seja empacotada com outros beans. Adicioná-la como uma alternativa no arquivo beans.xml reabilita efetivamente o bean, tornando-o disponível para injeção. Ao mover esse tipo de metadados para o arquivo beans.xml, é possível embutir versões diferentes do arquivo à várias implementações.

  19. Clique no botão Executar projeto ( botão Executar projeto ) para executar o projeto (alternativamente, pressione F6; fn-f6 no Mac). No navegador, clique no botão "Executar" exibido na página. Alterne de volta para o IDE e examine o registro do servidor GlassFish exibido na janela Saída (Ctrl-4; ⌘-4 no Mac).
    INFO: Item =  [Value=34, Limit=7] valid = false
    INFO: Item =  [Value=4, Limit=37] valid = true
    INFO: Item =  [Value=24, Limit=19] valid = true
    INFO: Item =  [Value=89, Limit=32] valid = false

    É possível notar que a implementação RelaxedItemValidator tem sido utilizada como o terceiro item exibido como válido, ao mesmo tempo que o valor fornecido (24) é maior que o limite informado (19).


Aplicação das anotações ciclo de vida para o Beans gerenciados

Neste exercício, será injetado um ItemErrorHandler na classe principal ItemProcessor. Como o FileErrorReporter é a única implementação da interface ItemErrorHandler, ela é selecionada como a injeção. Para configurar as ações especificadas pelo ciclo de vida para a classe, é necessário utilizar as anotações @PostConstruct e @PreDestroy a partir das especificações do Bean gerenciado (incluídas no JSR 316: Plataforma Java, Especificação Enterprise Edition 6).

O diagrama CDI mostra os objetos criados neste exercício.

Prosseguindo com o exemplo, crie uma interface ItemErrorHandler para manipular itens inválidos ao serem descobertos.

  1. Na janela Projetos, clique com o botão direito do mouse no pacote exercício3 e selecione Novo > Interface Java.
  2. No assistente Interface Java, digite ItemErrorHandler como o nome da classe e, em seguida, insira exercício3 como o pacote. Clique em Terminar.

    A nova interface é gerada e aberta no editor.

  3. Adicione o método chamado handleItem() que utiliza um objeto Item como um argumento.
    public interface ItemErrorHandler {
        void handleItem(Item item);
    }

    (Utilize a dica do editor para adicionar a declaração de importação para o exercise2.Item.)

  4. Comece com a implementação do ItemErrorHandler com um manipulador falso chamado FileErrorReporter que salva os detalhes do item num arquivo.

    Na janela Projetos, clique com o botão direito do mouse no pacote exercício3 e selecione Nova > Classe Java. Nome da classe FileErrorReporter e clique em Terminar.

  5. Faça com que o FileErrorReporter implemente o ItemErrorHandler e substitua o método handlerItem() como a seguir.
    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 declaração de importação para o exercise2.Item.)

    Você deseja abrir o arquivo antes de começar a manusear itens, portanto, deixe-o aberto enquanto o processo quando o conteúdo é adicionado ao arquivo, e a seguir feche o arquivo quando processamento for concluído. Você poderia adicionar manualmente os métodos initProcess() e finishProcess() ao bean de reporte 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 anotações do ciclo de vida da especificação do Bean gerenciado (incluídas no JSR 316: Java Platform, Especificações 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 é construído e qualquer dependência do bean tenha sido injetada. Da mesma forma, um método anotado @PreDestroy é chamado um pouco antes do bean ser descartado pelo recipiente.

  6. Adicione os seguintes métodos init() e release() com as anotações correspondentes @PostConstruct e @PreDestroy.
    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");
        }
    }
  7. 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). Declarações de importações para javax.annotation.PostConstruct e javax.annotation.PreDestroy são adicionadas à parte superior do arquivo.
  8. Finalmente, adicione o novo bean ItemErrorHandler ao ItemProcessor.
    @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 declaração de importação para o exercise3.ItemErrorHandler.)

  9. Clique no botão Executar projeto ( botão Executar projeto ) para executar o projeto (Alternativamente, pressione F6; fn-f6 no Mac). No navegador, clique no botão "Executar" exibido na página. Alterne de volta para o IDE e examine o registro do servidor GlassFish exibido na janela Saída (Ctrl-4; ⌘-4 no Mac).
    INFO: Creating file error reporter
    INFO: Saving  [Value=34, Limit=7] to file
    INFO: Saving  [Value=89, Limit=32] to file
    INFO: Closing file error reporter

Consulte também

Implementações diferentes de aplicativos podem utilizar regras diversas para manipular itens inválidos, tal como a rejeição de um item, o envio de notificações aos indivíduos, a sinalização destes ou simplesmente listá-los no arquivo de saída. Além disso, é possível fazer uma combinação destas regras (ex., rejeitar um pedido, enviar um e-mail a um representante de vendas e listar o pedido num arquivo). Uma maneira excelente de manipular este tipo de problema multifacetado é utilizar os eventos. Os eventos CDI são mencionados no artigo final desta série:

Para mais informações sobre o CDI e o Java EE, consulte os recursos a seguir.