Java EE 6 @ javax.annotation.ManagedBean vs. @ javax.inject.Named vs. @ javax.faces.ManagedBean

107

Eu sinto que há uma pequena bagunça na especificação do Java EE 6. Existem vários conjuntos de anotações.

Temos javax.ejbanotações como @Statefule @Statelesspara a criação de EJBs.

Também existe um @javax.annotation.ManagedBeanrecurso para criar um bean gerenciado.

Existem anotações em javax.enterprise.contextlike @SessionScopede @RequestScoped.

Além do mais, também há anotações @ManagedBeane @SessionScoped/ @RequestScopedno javax.faces.beanpacote.

E para complicar ainda mais os eventos, existe um pacote javax.injectcom @Namedanotações.

Alguém pode descrever como eles se relacionam um com o outro?

Onde posso usar @EJB, @Injectou @ManagedProperypara injetar outros grãos?

Piotr Gwiazda
fonte
Veja também: stackoverflow.com/questions/4684112/…
Arjan Tijms

Respostas:

194

Em primeiro lugar, deixe-me fazer alguns esclarecimentos:

Definição de bean gerenciado : geralmente um bean gerenciado é um objeto cujo ciclo de vida (construção, destruição, etc.) é gerenciado por um contêiner.

Em Java ee temos muitos containers que gerenciam o ciclo de vida de seus objetos, como container JSF, container EJB, container CDI, container Servlet, etc.

Todos esses contêineres funcionam de forma independente, eles inicializam na inicialização do servidor de aplicativos e examinam as classes de todos os artefatos, incluindo jar, ejb-jar, war e arquivos ear em tempo de implantação e reúnem e armazenam alguns metadados sobre eles, então quando você precisa de um objeto de uma classe em tempo de execução, eles fornecerão instâncias dessas classes e, após terminar o trabalho, eles as destruirão.

Portanto, podemos dizer que temos:

  • Feijões gerenciados JSF
  • Feijão gerenciado CDI
  • Feijões gerenciados EJB
  • E mesmo Servlets são beans gerenciados porque são instanciados e destruídos por um contêiner, que é um contêiner de servlet.

Portanto, quando você vir a palavra Managed Bean, deve perguntar sobre o contexto ou tipo dela. (JSF, CDI, EJB, etc.)

Então você pode perguntar por que temos muitos desses contêineres: AFAIK, os caras do Java EE queriam ter uma estrutura de injeção de dependência, mas não conseguiram reunir todos os requisitos em uma especificação porque não podiam prever os requisitos futuros e criaram EJB 1.0 e então 2.0 e depois 3.0 e agora 3.1, mas o objetivo do EJB era apenas para alguns requisitos (transação, modelo de componente distribuído, etc).

Ao mesmo tempo (em paralelo), eles perceberam que precisavam oferecer suporte ao JSF também, então eles fizeram beans gerenciados JSF e outro contêiner para os beans JSF e o consideraram um contêiner DI maduro, mas ainda não era um contêiner completo e maduro.

Depois disso, Gavin King e alguns outros caras legais;) fizeram CDI, que é o contêiner de DI mais maduro que já vi. CDI (inspirado em Seam2, Guice e Spring) foi feito para preencher a lacuna entre JSF e EJB e muitas outras coisas úteis como injeção de pojo, métodos de produção, interceptores, decoradores, integração SPI, muito flexível, etc. e pode até fazer o que os beans gerenciados EJB e JSF estão fazendo, então podemos ter apenas um contêiner de DI maduro e poderoso. Mas por alguma compatibilidade com versões anteriores e razões políticas, os caras do Java EE querem mantê-los !!!

Aqui você pode encontrar a diferença e os casos de uso para cada um desses tipos:

JSF Managed Beans, CDI Beans e EJBs

O JSF foi inicialmente desenvolvido com seu próprio bean gerenciado e mecanismo de injeção de dependência que foi aprimorado para JSF 2.0 para incluir beans baseados em anotação. Quando o CDI foi lançado com o Java EE 6, era considerado o framework de bean gerenciado para aquela plataforma e, claro, os EJBs os desatualizaram, já que existem há mais de uma década.

O problema, claro, é saber qual usar e quando usá-los.

Vamos começar com os beans gerenciados JSF mais simples.

JSF Managed Beans

Resumindo, não os use se estiver desenvolvendo para Java EE 6 e usando CDI. Eles fornecem um mecanismo simples para injeção de dependência e definição de beans de apoio para páginas da web, mas são muito menos poderosos do que os beans CDI.

Eles podem ser definidos usando a @javax.faces.bean.ManagedBeananotação que leva um parâmetro de nome opcional. Este nome pode ser usado para fazer referência ao bean a partir das páginas JSF.

O escopo pode ser aplicado ao bean usando um dos diferentes escopos definidos no javax.faces.beanpacote, que incluem a solicitação, sessão, aplicativo, visualização e escopos personalizados.

@ManagedBean(name="someBean")
@RequestScoped
public class SomeBean {
    ....
    ....
}

Os beans JSF não podem ser misturados com outros tipos de beans sem algum tipo de codificação manual.

Feijão CDI

CDI é a estrutura de gerenciamento de bean e injeção de dependência que foi lançada como parte do Java EE 6 e inclui um recurso de bean gerenciado completo e abrangente. Os beans CDI são muito mais avançados e flexíveis do que os beans gerenciados JSF simples. Eles podem fazer uso de interceptores, escopo de conversação, eventos, injeção de segurança de tipo, decoradores, estereótipos e métodos produtores.

Para implementar os beans CDI, você deve colocar um arquivo chamado beans.xml em uma pasta META-INF no classpath. Depois de fazer isso, cada bean no pacote se torna um bean CDI. Existem muitos recursos no CDI, muitos para cobrir aqui, mas como uma referência rápida para recursos do tipo JSF, você pode definir o escopo do bean CDI usando um dos escopos definidos no javax.enterprise.contextpacote (ou seja, solicitação, conversação , sessão e escopos de aplicativo). Se quiser usar o bean CDI de uma página JSF, você pode dar um nome a ele usando a javax.inject.Namedanotação. Para injetar um bean em outro bean, você anota o campo com javax.inject.Injectanotação.

@Named("someBean")
@RequestScoped
public class SomeBean {

    @Inject
    private SomeService someService;
}

A injeção automática como a definida acima pode ser controlada através do uso de qualificadores que podem ajudar a combinar a classe específica que você deseja injetar. Se você tiver vários tipos de pagamento, poderá adicionar um qualificador para saber se é assíncrono ou não. Embora você possa usar a @Namedanotação como um qualificador, não deveria, pois ela é fornecida para expor os beans em EL.

O CDI lida com a injeção de beans com escopos incompatíveis por meio do uso de proxies. Por causa disso, você pode injetar um bean com escopo de solicitação em um bean com escopo de sessão e a referência ainda será válida em cada solicitação porque, para cada solicitação, o proxy se reconecta a uma instância ativa do bean com escopo de solicitação.

O CDI também tem suporte para interceptores, eventos, o novo escopo de conversação e muitos outros recursos que o tornam uma escolha muito melhor em relação aos beans gerenciados JSF.

EJB

Os EJBs são anteriores aos beans CDI e, de alguma forma, são semelhantes aos beans CDI e, de outras maneiras, muito diferentes. Primeiramente, as diferenças entre os beans CDI e EJBs é que os EJBs são:

  • Transacional
  • Remoto ou local
  • Capaz de passivar beans com estado, liberando recursos
  • Capaz de fazer uso de temporizadores
  • Pode ser assíncrono

Os dois tipos de EJBs são chamados de stateless e stateful. EJBs sem estado podem ser considerados como beans de uso único thread-safe que não mantêm nenhum estado entre duas solicitações da web. EJBs com estado mantêm o estado e podem ser criados e permanecer em funcionamento pelo tempo que forem necessários até que sejam descartados.

Definir um EJB é simples, basta adicionar uma anotação javax.ejb.Statelessou javax.ejb.Statefulà classe.

@Stateless
public class BookingService {

  public String makeReservation(Item Item, Customer customer) {
    ...
    ...
  }
}

Os beans sem estado devem ter um escopo dependente, enquanto um bean de sessão com estado pode ter qualquer escopo. Por padrão, eles são transacionais, mas você pode usar a anotação de atributo de transação.

Embora os EJBs e os beans CDI sejam muito diferentes em termos de recursos, escrever o código para integrá-los é muito semelhante, já que os beans CDI podem ser injetados em EJBs e os EJBs podem ser injetados em beans CDI. Não há necessidade de fazer qualquer distinção ao injetar um no outro. Novamente, os diferentes escopos são tratados pelo CDI por meio do proxy. Uma exceção a isso é que o CDI não oferece suporte à injeção de EJBs remotos, mas isso pode ser implementado escrevendo um método de produtor simples para ele.

A javax.inject.Namedanotação, bem como quaisquer qualificadores, podem ser usados ​​em um EJB para combiná-lo com um ponto de injeção.

Quando usar qual feijão

Como saber quando usar qual bean? Simples.

Nunca use beans gerenciados JSF, a menos que esteja trabalhando em um contêiner de servlet e não queira tentar fazer o CDI funcionar no Tomcat (embora haja alguns arquétipos Maven para isso, então não há desculpa).

Em geral, você deve usar os beans CDI, a menos que precise da funcionalidade avançada disponível nos EJBs, como funções transacionais. Você pode escrever seu próprio interceptor para tornar os beans CDI transacionais, mas, por enquanto, é mais simples usar um EJB até que o CDI obtenha os beans CDI transacionais que estão logo ali. Se você estiver preso em um contêiner de servlet e estiver usando CDI, as transações escritas à mão ou seu próprio interceptor de transação são a única opção sem EJBs.

Se você precisa usar @ViewScopedem CDI, você deve

  • usar seam-faces ou módulo CODI MyFaces . apenas adicione um deles ao seu classpath e @ViewScopedfuncionará no CDI. MyFaces CODI tem um suporte ainda mais sólido de @ViewScoped
  • use MyFaces CODI's @ViewAccessScoped, é uma extensão escrita em cima do CDI pelo Apache, basta fazer o download e usar @ViewAccessScopedanotação em vez de @ViewScoped.
  • Use o CDI @ConversationScopede torne-o de longa duração. Veja aqui para mais informações .
  • Use a anotação Omnifaces @ViewScoped

Algumas peças roubadas daqui .

Mehdi
fonte
3
Isso é ótimo! Obrigado! Para completar, apenas diga como injetar CDI ou bean EJB no bean JSF. É a @ManagedProperty("#{someBean})"maneira correta?
Piotr Gwiazda de
2
Não! não vai funcionar. basta ligar o seu jsf feijão conseguiu CDI bean gerenciado anotando-lo usando @Namede @javax.enterprise.context.RequestScopede injeção de uso CDI usando anotação @Inject. não use beans gerenciados jsf se não for necessário;).
Mehdi
3
> Os caras do JEE querem mantê-los !!! - É um pouco mais sutil do que isso. O CDI terminou bem tarde no ciclo do Java EE 6 e tanto o JSF 2 quanto o JAX-RS já estavam prontos. Eles tinham resp melhorado. já introduziu sua própria instalação de feijão gerenciado. Se o CDI estivesse disponível um pouco antes, as coisas poderiam ter sido diferentes. No Java EE 7, o JSF adotará o CDI e o javax.faces.bean eventualmente será descontinuado (porém, a reprovação é um processo lento no Java EE, que é bom e ruim).
Arjan Tijms
3
Quando você diz: Para implantar os beans CDI, você deve colocar um arquivo chamado beans.xml em uma pasta META-INF no classpath. Depois de fazer isso, cada bean no pacote se torna um bean CDI. Você quer dizer que cada bean também se torna um bean CDI além do que era? E se eu tiver JSF ManagedBeans com ManagedBean e ViewScoped. Eles ainda são JSF Managed Beans, certo?
Koray Tugay
3
Alguém capaz de fazer uma atualização para o Java EE 7 neste ótimo artigo?
Martijn Burger
7

Sim, isso pode ser confuso.

Por algumas razões históricas ehm , JSF e CDI estão usando as mesmas anotações para escopos, mas de pacotes diferentes.

Como você provavelmente deve estar adivinhando, eles javax.faces.beansão da especificação JSF e não estão relacionados ao CDI. Não os use, a menos que tenha um bom motivo para fazê-lo. E nunca, jamais, misture-os com as anotações CDI de javax.ejb. Isso produzirá uma lista infinita de bugs e anomalias sutis.

Eu geralmente recomendo que você folheie as primeiras (ou até mais) páginas da excelente documentação do Weld . Isso deve colocá-lo no caminho certo para o Java EE 6.

E fique à vontade para postar mais perguntas aqui.

Jan Groth
fonte
Na verdade, tenho duas perguntas: 1. Costumo achar o escopo da visão muito útil. Preciso usar anotações JSF então? 2. Isso significa que @javax.annotation.ManagedBeané inútil, já que o CDI trata todas as classes como beans gerenciados, certo?
Piotr Gwiazda de
Não exatamente. Você precisará conectar os escopos JSF ao CDI com, por exemplo, o Seam Faces. E sim, @ManagedBeans não são necessários se você tiver um beans.xml no arquivo jar relevante. Ah, e se você tiver mais perguntas, é melhor começar um novo tópico antes de nos perdermos na seção de comentários.
janeiro groth
3

Como não há respostas específicas sobre @javax.annotation.ManagedBean, aqui está um link para a resposta de uma pergunta semelhante: Beans de apoio (@ManagedBean) ou Beans de CDI (@Named)? . A especificação pode ser encontrada em http://download.oracle.com/otndocs/jcp/managed_beans-1.0-fr-eval-oth-JSpec/ . Portanto, parece-me que @javax.annotation.ManagedBeanera para ser uma generalização de @javax.faces.bean.ManagedBean.

Pelo que eu percebi, o JSF Managed Beans está sendo eliminado em favor dos CDI Beans (talvez ficando obsoleto do JSF 2.3?), Então acho que @javax.annotation.ManagedBeanestá se tornando cada vez mais obsoleto agora.

Hein Blöd
fonte
@Namedirá substituir @ManagedBeanno futuro?
Thufir
1
Eu li várias declarações de diferentes especialistas em Java EE que prevêem que os @Namedbeans CDI substituirão o JSF @ManagedBeans, por exemplo, em stackoverflow.com/questions/4347374/… , BalusC diz "A expectativa é que @ManagedBean e amigos sejam descontinuados de acordo com o Java EE 8. ".
Hein Blöd