Beans de apoio (@ManagedBean) ou Beans CDI (@Named)?

109

Acabei de começar a ler Core JavaServer Faces, 3ª ed. e eles dizem isso (ênfase minha):

É um acidente histórico que haja dois mecanismos separados, os beans CDI e os beans gerenciados JSF, para os beans que podem ser usados ​​nas páginas JSF. Sugerimos que você use os beans CDI, a menos que seu aplicativo deva funcionar em um executor de servlet simples, como o Tomcat.

Por quê? Eles não fornecem nenhuma justificativa. Tenho usado @ManagedBeanpara todos os beans em um aplicativo de protótipo em execução no GlassFish 3 e realmente não notei nenhum problema com isso. Não me importo especialmente em migrar de @ManagedBeanpara @Named, mas quero saber por que deveria me preocupar .

Matt Ball
fonte
4
@Bozho: essa pergunta é bem parecida, mas depois de ler a resposta de Pascal algumas vezes, ainda não entendo porque o CDI é muito superior. Não conheço CDI e fico feliz em saber que é "melhor". Por que está melhor?
Matt Ball
"a menos que seu aplicativo deva funcionar em um runner de servlet simples como o Tomcat" Eu só uso o tomcat e recomendo fortemente o CDI. Tomcat pode suportar muito bem
Karl Kildén
1
@ KarlKildén "executor de servlet simples" refere-se a um contêiner de servlet não compatível com CDI. No momento em que este artigo foi escrito, o Tomcat não suportava CDI, exceto com um pouco de magia.
Thorbjørn Ravn Andersen,

Respostas:

64

O CDI é preferível ao JSF simples porque o CDI permite a injeção de dependência em todo o JavaEE. Você também pode injetar POJOs e permitir que sejam gerenciados. Com o JSF, você só pode injetar um subconjunto do que é possível com o CDI.

Bozho
fonte
Então, basicamente, posso injetar uma instância de quase qualquer classe (desde que tenha "as coisas certas" - o que é, apenas um construtor sem argumentos? ) Com CDI, enquanto tenho que usar @ManagedBeanse quiser injetá-la com JSF?
Matt Ball
3
@MattBall Matt depois de anos, você pode comentar sobre essa migração?
Koray Tugay
5
@KorayTugay Eu não toquei neste código desde junho de 2011, mas eu mudei para CDI e as coisas funcionaram bem. Estou feliz em responder a quaisquer perguntas específicas o melhor de minha memória, se você as tiver.
Matt Ball
170

Use CDI.

De acordo com o JSF 2.3, @ManagedBeanestá obsoleto . Consulte também o problema de especificação 1417 . Isto significa que não há mais uma razão para escolher @ManagedBeanmais @Named. Isso foi implementado pela primeira vez no Mojarra 2.3.0 beta versão m06.

insira a descrição da imagem aqui


História

A principal diferença é que @ManagedBeané gerenciado pelo framework JSF e está @ManagedPropertydisponível apenas para outros beans gerenciados JSF. @Namedé gerido pelo servidor de aplicativos (o recipiente) via quadro CDI e é via @Injectdisponível para qualquer tipo de recipiente artefato gerido como @WebListener, @WebFilter, @WebServlet, @Path, @Stateless, etc e até mesmo um JSF @ManagedBean. Do outro lado, @ManagedPropertyse não trabalhar dentro de uma @Namedou qualquer outro recipiente artefato gerenciado. Funciona realmente apenas por dentro @ManagedBean.

Outra diferença é que o CDI realmente injeta proxies que delegam à instância atual no escopo de destino por solicitação / thread (por exemplo, como os EJBs são injetados). Esse mecanismo permite injetar um bean de escopo mais restrito em um bean de escopo mais amplo, o que não é possível com JSF @ManagedProperty. O JSF "injeta" aqui a instância física diretamente chamando um setter (é exatamente por isso que um setter é necessário, embora não seja necessário com @Inject).

Embora não seja uma desvantagem direta - existem outras maneiras - o escopo do @ManagedBeané simplesmente limitado. Da outra perspectiva, se você não quiser expor "demais" para @Inject, também pode apenas manter seus beans gerenciados @ManagedBean. É como protectedversus public. Mas isso realmente não conta.

Pelo menos, no JSF 2.0 / 2.1, a principal desvantagem de gerenciar beans de apoio JSF por CDI é que não há equivalente de CDI @ViewScoped. O @ConversationScopedchega perto, mas ainda requer iniciar e parar manualmente e anexar um cidparâmetro de solicitação feio aos URLs resultantes. MyFaces CODI torna isso mais fácil, conectando JSFs javax.faces.bean.ViewScopeda CDI de forma totalmente transparente, de modo que você possa simplesmente fazer @Named @ViewScoped, no entanto, isso anexa um windowIdparâmetro de solicitação feio a URLs resultantes, também na navegação simples de página a página. OmniFaces resolve tudo isso com um verdadeiro CDI @ViewScopedque realmente vincula o escopo do bean ao estado de exibição JSF em vez de a um parâmetro de solicitação arbitrário.

JSF 2.2 (que é lançado 3 anos após esta pergunta / resposta) oferece uma nova @ViewScopedanotação totalmente compatível com CDI fora da caixa no sabor de javax.faces.view.ViewScoped. O JSF 2.2 vem com um CDI apenas @FlowScopedque não tem um @ManagedBeanequivalente, empurrando os usuários do JSF para o CDI. A expectativa é que @ManagedBeane amigos sejam descontinuados de acordo com o Java EE 8. Se você ainda estiver usando @ManagedBean, é altamente recomendável mudar para o CDI para estar preparado para caminhos de atualização futuros. O CDI está disponível em containers compatíveis com o Java EE Web Profile, como WildFly, TomEE e GlassFish. Para o Tomcat, você deve instalá-lo separadamente, exatamente como já fez para o JSF. Veja também Como instalar o CDI no Tomcat?

BalusC
fonte
4
Eu criei beans.xml, converti @ManagedBeanbeans de apoio em @Namede converti @ManagedPropertyem @Inject. Tudo está bem com o mundo. No entanto, se eu alterar minhas @EJBanotações para @Inject, a implantação falhará ( org.jboss.weld.exceptions.DeploymentException) com mensagem WELD-001408 Injection point has unsatisfied dependencies. Devo realmente usar @Injectpara injetar EJBs sem interface em um @Namedbean, ou devo continuar @EJB? Os EJBs são empacotados em um EJB JAR, no mesmo EAR que o WAR que contém meus beans CDI.
Matt Ball
Deve funcionar. Você ainda está enfrentando esse problema com a versão atual do Weld?
BalusC de
Infelizmente, não sei dizer. Esta pergunta é de 2 empregadores e> 2 anos atrás. Com base em meu antigo comentário sobre a resposta de Bozho, devo ter mudado para CDI / @Named.
Matt Ball,
"MyFaces CODI torna mais fácil ao conectar de forma totalmente transparente o javax.faces.bean.ViewScoped do JSF ao CDI para que você possa apenas fazer @Named @ViewScoped, no entanto, que anexa um parâmetro de solicitação windowId feio aos URLs resultantes, também na navegação página a página simples." Observe que com DeltaSpike isso não é mais verdadeiro. Você pode desativar os parâmetros de URL dsId e windowId, se não precisar do Window Scope.
JanM
1
@Jan: Enquanto isso, OmniFaces também tem um JSF 2.2-like @ViewScopedpara JSF 2.0 / 2.1: showcase.omnifaces.org/cdi/ViewScoped
BalusC
16

Com Java EE 6 e CDI você tem opções diferentes para Managed Beans

  • @javax.faces.bean.ManagedBeanrefere-se a JSR 314 e foi introduzido com JSF 2.0. O objetivo principal era evitar a configuração no arquivo faces-config.xml para usar o bean dentro de uma página JSF.
  • @javax.annotation.ManagedBean(“myBean”) é definido por JSR 316. Ele generaliza os beans gerenciados JSF para uso em outro lugar em Java EE
  • @javax.inject.Named(“myBean”) são quase iguais ao anterior, exceto que você precisa de um arquivo beans.xml na pasta web / WEB-INF para ativar o CDI.
h2mch
fonte
1
Qual é a diferença entre os dois primeiros?
Matt Ball
O objetivo da primeira anotação é / era substituir a configuração do bean no faces-config.xml para uso no JSF. O segundo copia o conceito para o "container java ee 6". Ele tem mais funções (como anotações @PostConstruct e @PreDestroy), mas também pode ser acessado pela Página JSF (com Expression Language).
h2mch
1
por que você precisa de um beans.xmlarquivo? Isso ainda é verdade hoje?
Thufir
2
Não, com JavaEE7 você não precisa mais do beans.xml. consulte docs.oracle.com/javaee/7/tutorial/doc/cdi-adv001.htm
h2mch
1
Com o JavaEE7 você não precisa do beans.xml: docs.oracle.com/javaee/7/tutorial/cdi-adv001.htm (link correto) blogs.oracle.com/theaquarium/entry/… (Ativação CDI padrão em Java EE 7)
M. Atif Riaz
2

Eu estava usando CDI no GlassFish 3.0.1, mas para fazê-lo funcionar, tive que importar o framework Seam 3 (Weld). Isso funcionou muito bem.

No GlassFish 3.1 CDI parou de funcionar, e o Seam Weld parou de funcionar com ele. Eu abri um bug sobre isso, mas não vi corrigido ainda. Tive que converter todo o meu código para usar as anotações javax.faces. *, Mas pretendo voltar ao CDI assim que ele começar a funcionar.

Concordo que você deve usar CDI, mas um problema que ainda não vi resolvido é o que fazer com a anotação @ViewScoped. Eu tenho muito código que depende disso. Não está claro se @ViewScoped funciona se você não estiver usando @ManagedBean com ele. Se alguém puder esclarecer isso eu agradeceria.

AlanObject
fonte
-1

Um bom motivo para mudar para CDI: você poderia ter um recurso com escopo de sessão comum (perfil de usuário, por exemplo) @Injectinstalado em beans gerenciados JSF e serviços REST (ou seja, Jersey / JAX-RS).

Por outro lado, @ViewScopedé um motivo convincente para manter o JSF @ManagedBean- especialmente para qualquer coisa com AJAX significativo. Não existe um substituto padrão para isso no CDI.

Parece que ele pode ter algum suporte para uma @ViewScopedanotação semelhante a um para beans CDI, mas não brinquei com ele pessoalmente.

http://seamframework.org/Seam3/FacesModule

wrschneider
fonte