Artigo Java Magazine 39 - Java EE 5

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (0)  (0)

Artigo publicado pela Java Magazine 39.

Esse artigo faz parte da revista Java Magazine edição 39. Clique aqui para ler todos os artigos desta edição

 imagem_pdf.jpg

Java EE 5

Um Enterprise Edition muito mais fácil

Explorando a nova versão do Java corporativo: anotações, injeção de dependências, novas JSRs e um exemplo prático no servidor open source Glassfish

Ao reler meu primeiro artigo na Java Magazine, "J2EE Fundamental" (Edição 1, julho de 2002), abordando o recém-lançado J2EE 1.3, pude verificar como o status da plataforma mudou. Eram apresentados fundamentos como containers, servidores de aplicações e EJB, até então pouco familiares para muitos desenvolvedores. Servidores J2EE eram ferramentas caras e pesadas, e a portabilidade ainda deixava a desejar para os padrões do Java. Alguns componentes, como os Entity Beans, estavam francamente imaturos – isso quando não já tinham sido descartados por muitos. O artigo terminava com uma seção "Web services: o futuro", já anunciando o J2EE 1.4 (lançado em novembro de 2003), mas apontando os problemas de compatibilidade de padrões ainda em definição – hoje em dia, poderíamos reclamar que já existem padrões de Web Services até em demasia.

Passados quatro anos, a plataforma, agora rebatizada Java EE, dispensa apresentações, tendo se constituído num componente obrigatório do conhecimento de qualquer desenvolvedor Java atuando no "lado do servidor" (server-side). Mesmo frameworks que correm por fora e ganharam prestígio e popularidade, como Spring e Hibernate, têm ocupado um lugar mais complementar do que alternativo em relação ao Java EE. E numa exibição surpreendente de resposta às direções escolhidas pela comunidade, o novo Java EE 5 adere a práticas popularizadas por estas outras soluções, como inversão de controle, uso mais intenso de metadados e persistência baseada em POJOs (Plain Old Java Objects).

Este artigo inicia com uma discussão geral sobre esta grande atualização da plataforma. Diferentemente de outros artigos desta coluna, não entraremos em detalhe sobre APIs e funcionalidades específicas, o que seria pouco viável devido à extensão da plataforma. Esta necessidade será melhor servida por artigos futuros especializados em temas como JPA (coberto nesta edição), EJB etc. Aqui nosso objetivo é fornecer, mais uma vez, uma visão conceitual. Mas agora assumimos que o leitor já possui familiaridade básica com a plataforma J2EE. Assim, podemos enfocar as novidades, e analisar e discutir a natureza e as motivações por trás de cada mudança dessa atualização que pode mudar radicalmente sua rotina de desenvolvimento de aplicações "Enterprise Edition". E para começar uma exploração prática, o quadro "Glassfish: O Java EE open source" mostra como instalar a implementação de referência (RI) desta plataforma, e desenvolver uma aplicação Java EE 5 simples com o IDE NetBeans 5.5.

Java EE 5: Produtividade Corporativa

Se o release anterior, J2EE 1.4, era a versão dos web services, o Java EE 5 é a versão da produtividade. Não por coincidência, é o mesmo foco do Java SE 5.0, especialmente com a nova sintaxe de anotações.

As anotações são o veículo principal das melhorias de produtividade do Java EE 5. Quer que uma classe seja um Stateless Session Bean? Basta declarar "@Session class MinhaClasse {...}". Precisa expor a funcionalidade de uma classe como um web service? Use a tag @WebService. E para conectar a um DataSource? Nada de código JNDI – InitialContext, lookup(), narrow(), tratamento de exceções – basta usar a anotação apropriada, como "@Resource(name="jdbc/minhaDS") DataSource minhaDS;".

POJOs e anotações versus descritores

O paradigma de programação do Java EE 5 dá um guinada espetacular, abandonando boa parte da burocracia do tradicional J2EE em favor de uma opção preferencial pela simplicidade. A "programação baseada em POJOs[1]" é fortemente suportada. Veja algumas novas características:

·         Temos POJOs no lugar de implementação de interfaces. Não precisam mais ser escritos centenas de métodos completamente vazios, como ejbActivate(), só porque uma interface de EJB os exige.

·         É usada a Injeção de Dependências em vez de aborrecidos lookups na JNDI.

·         As anotações assumem o lugar de descritores XML.

·         Há muitos comportamentos default que evitam a necessidade de especificar opções comuns, seja com descritores ou com anotações. Por exemplo, um @WebMethod (método de web service) suporta anotações @WebParam para os parâmetros, mas estas são opcionais. Na sua falta, o container assumirá defaults bons para a maioria dos usos (como holder=Mode.IN).

 

Mas será que este paradigma de programação é sempre melhor? Em relação às anotações, que são o instrumento fundamental do novo modelo, já as questionamos em artigos anteriores, em seções com títulos como "Cuidados com as anotações" e "Uma crítica às anotações". O motivo de tanta precaução é que uma revisão tão radical no processo de desenvolvimento não deve ser abordada sem cuidado e visão crítica.

Felizmente, com a forma que o Java EE 5 tomou, esses temores não se concretizaram. Em especial, os descritores ainda são suportados (o que já é bom por motivo de compatibilidade) e eles têm prioridade sobre informações declaradas por anotações. Isso evita que as anotações eliminem a flexibilidade garantida pelos descritores.

Por exemplo, numa classe persistente você pode usar uma anotação @Table(name="TAB") para determinar que os objetos da classe serão persistidos na tabela “TAB”. Isso é muito conveniente, mas o que acontece se um dia o nome da tabela tiver que mudar? No J2EE tradicional (EJB/CMP), bastaria alterar o descritor. No Java EE 5 poderíamos alterar a anotação @Table, mas isto não é obrigatório. Podemos também criar um descritor e informar nele o nome atualizado da tabela. No caso de redundância (mesma informação em anotações e no descritor), o container dará preferência ao descritor. Preserva-se assim a flexibilidade dos descritores – e só há o trabalho de manipulá-los quando for realmente necessário.

Mas note que estes casos são a minoria. Na prática, as oportunidades de adaptar aplicações a mudanças no ambiente externo mexendo apenas no descritor só costumam ocorrer em casos triviais, como mudanças nos nomes JNDI de DataSources ou filas de JMS, causadas talvez por uma migração de ambiente (ex.: homologação para produção). E mesmo nestes casos, a indireção proporcionada pelas resource references (J2EE 1.3+) já evita a necessidade de alterações até nos nomes JNDI "internos", usados nos descritores e no código.

Observamos que existem algumas características, consideradas "estruturais", que se definidas por anotações não são redefiníveis por descritores. Por exemplo, novamente com EJBs, anotações como @Stateless e @Stateful denotam os diferentes tipos de Session Beans. Mas se uma classe for anotada com @Stateless, não será possível, pelo descritor, transformá-la num EJB Stateful. O motivo é simples: a diferença entre um bean Stateless e um Stateful não está apenas no descritor – beans Stateful, presumivelmente, mantêm algum estado interno, enquanto beans Stateless não o fazem, portanto transformar um tipo no outro exige alterações de código de qualquer maneira.

Anotações versus Orientação a Objetos

As anotações constituem uma alternativa a técnicas mais tradicionais na programação OO, como herança ou design patterns. O J2EE tradicional, como sabemos, é fortemente baseado em herança. Um Entity Bean, por exemplo, é uma classe que implementa a interface javax.ejb.EntityBean, o que obriga a definir sete métodos (como ejbActivate(), ejbLoad() etc.), que na sua maioria são desnecessários para a maior parte dos beans. Há certamente algo errado numa arquitetura que obriga as aplicações a definir até sete métodos vazios para cada entidade de negócio. (Lembrando que em Java, nem sempre é uma boa idéia usar classes-base que forneçam implementações default destas interfaces de framework, pois isto "queima" a oportunidade única de herança de implementação[2]).

Em oposição à rigidez da herança, as anotações enriquecem uma classe com comportamentos de forma muito mais granular. Há anotações por tipo, atributo, método, e até por parâmetro ou variável local. Assim, se o seu bean realmente precisa executar algum código especial após a ativação, basta implementar um método anotado por @PostActivate.

As anotações possuem uma vantagem crucial: são estaticamente tipadas. Podem ser verificadas e validadas de forma offline, o que evita toda uma categoria de bugs. O javac só verificará a correção sintática das anotações, por exemplo reclamando se você usar uma propriedade inexistente numa anotação; não reportará erros semânticos, ex.: uma propriedade @EJB.beanInterface com um valor que não seja uma interface local/remota de EJB. Mas as ferramentas de validação incluídas em IDEs com suporte a Java EE e em servidores de aplicações poderão fazer estas validações no momento da implantação ou antes, evitando que o bug fique oculto e "estoure" somente quando a aplicação já estiver em operação.

Injeção de Dependências

A persistência de POJOs, no estilo do Hibernate, tem chamado atenção como a grande novidade que o Java EE 5 pega emprestada de outros frameworks. Mas não menos importante é a Injeção de Dependências (ID). Para compreender a idéia fundamental da ID, podemos classificar as aplicações em três graus de evolução:

1. Todas as dependências (de configurações e de código) estão amarradas no código. Neste caso, mudar qualquer coisa exige alterar código, recompilar e reiniciar a aplicação. É o grau zero, hoje em dia só encontrado em aplicações de iniciantes ou em códigos descartáveis, como protótipos.

2. Dependências de configuração estão fora do código. A aplicação é parametrizada por informações carregadas a partir de arquivos, bancos de dados, diretórios ou outros locais externos. A alteração destes parâmetros pode ser feita por um não-desenvolvedor, não exige mudanças no código e talvez nem indisponibilidade. Por outro lado, dependências de código continuam amarradas. Em qualquer circunstância onde a classe A precisa utilizar a classe B, isto é feito com código, ex.:

class A {

  void m() {

      B b = new B();

      // usa b...

   }

}.

Alguns design patterns, como Abstract Factory e Service Locator, ajudam a encapsular e concentrar num só lugar a decisão de quais objetos instanciar ou utilizar, e permitem aos dependentes de um componente depender apenas de interfaces abstratas. Mas isso não é uma solução completa, pois as dependências de código continuam sendo resolvidas por código, ainda que de forma mais elegante e sem repetições. É neste ponto de evolução que se encontra a maioria das aplicações atuais bem escritas.

3. Uso de Injeção de Dependências. As dependências de código não são responsabilidade do código da aplicação, e sim de um runtime de Injeção de Dependências, que "injeta" em cada objeto-cliente os recursos dos quais ele depende. As regras que determinam como esta injeção é feita – qual classe instanciar e com quais parâmetros – ficam em metadados externos, que são manipulados pelo runtime de ID.

 

O exemplo mais comum de Injeção de Dependências, em aplicações Java EE, é o da comunicação com EJBs. Se você já programou com EJB, já deve ter visto ou escrito muito código como o da Listagem 1. Neste exemplo, na camada de apresentação de uma aplicação (no caso, uma GUI web implementada com o Struts), precisamos invocar um Session Bean que executa o login do usuário. Todo o código destacado em negrito não passa de "burocracia do J2EE". Veja quanta coisa precisamos fazer só para invocar um simples método login()"

A exibição deste artigo foi interrompida :(
Este post está disponível para assinantes MVP

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?