SeamFramework.orgCommunity Documentation
Um bean é usualmente uma classe de aplicação que contém lógica de negócio. Pode ser chamado diretamente a partir do código Java, ou pode ser invocado por meio da Unified EL. Um bean pode acessar recursos transacionais. As dependências entre beans são gerenciadas automaticamente pelo contêiner. A maioria dos beans são stateful e contextuais. O ciclo de vida de um bean é sempre gerenciado pelo contêiner.
Vamos voltar um segundo. O que realmente significa ser contextual? Uma vez que os beans podem ser stateful, é importante saber qual instância do bean eu tenho. Ao contrário de um modelo de componentes stateless (por exemplo, stateless session beans) ou um modelo de componentes singleton (como servlets, ou singleton beans), diferentes clientes de um bean vêem o bean em diferentes estados. O estado visível ao cliente depende de para qual instância do bean o cliente tem uma referência.
No entanto, como em um modelo stateless ou singleton, mas de modo diferente em stateful session beans, o cliente não controla o ciclo de vida da instância pela explícita criação e destruição dela. Em vez disso, o escopo do bean determina:
o ciclo de vida de cada instância do bean e
quais clientes compartilham uma referência para uma instância específica do bean.
Para uma dada thread em uma aplicação CDI, pode haver um contexto ativo associado com o escopo do bean. Este contexto pode ser único para a thread (por exemplo, se o bean possui escopo de solicitação), ou pode ser compartilhado com algumas outras threads (por exemplo, se o bean possui escopo de sessão) ou mesmo com todas as outras threads (se ele possui escopo de aplicação).
Os clientes (por exemplo, outros beans) executados no mesmo contexto verão a mesma instância do bean. Mas os clientes em um diferente contexto podem ver uma instância diferente (dependendo do relacionamento entre os contextos).
Uma grande vantagem do modelo contextual é que ele permite que stateful beans sejam tratados como serviços! O cliente não precisa se preocupar com o gerenciamento do ciclo de vida do bean que ele está usando, nem mesmo precisam saber o que é ciclo de vida. Os beans interagem passando mensagens, e as implementações do bean definem o ciclo de vida de seu próprio estado. Os beans são de baixo acoplamento porque:
eles interagem por meio de APIs bem definidas e públicas
seus ciclos de vida são completamente desacoplados
We can replace one bean with another different bean that implements the same interface and has a different lifecycle (a different scope) without affecting the other bean implementation. In fact, CDI defines a simple facility for overriding bean implementations at deployment time, as we will see in Seção 4.7, “Alternativos”.
Note que nem todos os clientes de um bean são eles próprios também beans. Outros objetos como servlets ou message-driven beans—que são por natureza objetos não injetáveis e não contextuais —podem também obter referências para beans por meio de injeção.
Já chega de acenar as mãos. Mais formalmente, a anatomia de um bean, de acordo com a especificação:
Um bean abrange os seguintes atributos:
Um conjunto (não vazio) de tipos de bean
Um conjunto (não vazio) de qualificadores
Um escopo
Opcionalmente, um nome EL do bean
Um conjunto de vinculações com interceptadores
Uma implementação do bean
Além disso, um bean pode ou não pode ser um bean alternativo.
Vamos ver o que toda esta nova terminologia significa.
Beans usualmente adquirem referências para outros beans por meio de injeção de dependência. Qualquer atributo injetado especifica um "contrato" que deve ser satisfeito pelo bean para ser injetado. O contrato é:
um tipo de bean, juntamente com
um conjunto de qualificadores.
Um tipo de bean é uma classe ou interface definida pelo usuário; um tipo que é visível ao cliente. Se o bean é um EJB session bean, o tipo do bean é a interface @Local
ou a classe do bean da visão local. Um bean pode possuir múltiplos tipos. Por exemplo, o seguinte bean possui quatro tipos de bean:
public class BookShop
extends Business
implements Shop<Book
> {
...
}
Os tipos de bean são BookShop
, Business
e Shop<Book>
, bem como o tipo implícito java.lang.Object
. (Observe que um tipo parametrizado é um tipo de bean válido).
Entretanto, este session bean possui somente as interfaces locais BookShop
, Auditable
e java.lang.Object
como tipos de bean, uma vez que a classe do bean, BookShopBean
, não é um tipo visível ao cliente.
@Stateful
public class BookShopBean
extends Business
implements BookShop, Auditable {
...
}
The bean types of a session bean include local interfaces and the bean class local view (if any). EJB remote interfaces are not considered bean types of a session bean. You can't inject an EJB using its remote interface unless you define a resource, which we'll meet in Capítulo 14, Recursos do ambiente de componentes Java EE.
Os tipos do bean podem ser limitados a um conjunto explícito, anotando o bean com a anotação @Typed
e listando as classes que devem ser os tipos do bean. Por exemplo, os tipos de bean desde bean foram restritos a Shop<Book>
, juntamente com java.lang.Object
:
@Typed(Shop.class)
public class BookShop
extends Business
implements Shop<Book
> {
...
}
Algumas vezes um tipo de bean sozinho não fornece informação suficiente para o contêiner saber qual bean injetar. Por exemplo, suponha que temos duas implementações da interface PaymentProcessor
: CreditCardPaymentProcessor
e DebitPaymentProcessor
. Injetar em um campo do tipo PaymentProcessor
introduz uma condição ambígua. Nestes casos, o cliente deve especificar algum qualidade adicional da implementação que ele está interessado. Modelamos esta categoria de "qualidade" usando um qualificador.
Um qualificador é uma anotação definida pelo usuário que é ela própria anotada com @Qualifer
. Uma anotação de qualificador é uma extensão do sitema de tipos. Ela nos permite desambiguar um tipo sem ter que recorrer a nomes baseados em strings. Aqui está um exemplo de uma anotação de qualificador:
@Qualifier
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
public @interface CreditCard {}
Você pode não estar acostumado a ver a definição de uma anotação. Na verdade, essa poderia ser a primeira vez que você encontrou uma. Com CDI, definições de anotação se tornará um artefato familiar conforme você for criando-os de vez em quando.
Preste atenção nos nomes das anotações embutidas em CDI e EJB. Você perceberá que elas são muitas vezes adjetivos. Nós encorajamos você a seguir esta convenção ao criar suas próprias anotações, uma vez que elas servem para descrever os comportamentos e papéis da classe.
Agora que temos definido uma anotação de qualificador, podemos utilizá-la para resolver a ambiguidade no ponto de injeção. O seguinte ponto de injeção possui o tipo de bean PaymentProcessor
e o qualificador @CreditCard
:
@Inject @CreditCard PaymentProcessor paymentProcessor
Para cada ponto de injeção, o contêiner pesquisa por um bean que satisfaça o contrato, um que tenha o tipo de bean e todos os qualificadores. Se ele encontrar exatamente um bean, ele injeta uma instância deste bean. Se ele não encontrar, ele reporta um erro ao usuário.
Como especificamos os qualificadores de um bean? Anotando a classe de bean, é claro! O seguinte bean possui o qualificador @CreditCard
e implementa o tipo de bean PaymentProcessor
. Portanto, ele satisfaz nosso ponto de injeção qualificado:
@CreditCard
public class CreditCardPaymentProcessor
implements PaymentProcessor { ... }
Se um bean ou um ponto de injeção não define explicitamente um qualificador, ele terá o qualificador padrão, @Default
.
That's not quite the end of the story. CDI also defines a simple resolution rule that helps the container decide what to do if there is more than one bean that satisfies a particular contract. We'll get into the details in Capítulo 4, Injeção e pesquisa programática de dependências.
O escopo de um bean define o ciclo de vida e a visibilidade de suas instâncias. O modelo de contexto da CDI é extensível, acomodando escopos arbitrários. No entanto, certos escopos importantes estão encorporados na especificação, e fornecidos pelo contêiner. Cada escopo é representado por um tipo de anotação.
Por exemplo, qualquer aplicação web pode possuir beans com escopo de sessão:
public @SessionScoped
class ShoppingCart implements Serializable { ... }
Uma instância de um bean com escopo de sessão está vinculada à sessão do usuário e é compartilhada por todas as solicitações executadas no contexto desta sessão.
Mantenha em mente que uma vez que um bean está vinculado a um contexto, ele permanece neste contexto até que o contexto seja destruído. Não existe modo algum para remover manualmente um bean daquele contexto. Se você não quer que o bean fique na sessão indefinitivamente, considere o uso de um outro escopo com um tempo de vida mais curto, como os escopos de solicitação e conversação.
Se um escopo não está explicitamente especificado, então o bean pertence a um escopo especial chamado de pseudo-escopo dependente. Os beans com este escopo vivem para servir o objeto no qual eles foram injetados, o que significa que seu ciclo de vida está vinculado ao ciclo de vida deste objeto.
We'll talk more about scopes in Capítulo 5, Escopos e contextos.
Se você quer referenciar um bean em um código não-Java que suporta expressões Unified EL, por exemplo, em uma página JSP ou JSF, você deve assinar o bean com um nome EL.
O nome EL é especificado usando a anotação @Named
, como mostrado aqui:
public @SessionScoped @Named("cart")
class ShoppingCart implements Serializable { ... }
Agora podemos facilmente usar o bean em qualquer página JSF ou JSP:
<h:dataTable value="#{cart.lineItems}" var="item">
...
</h:dataTable
>
A anotação @Named
não é o que torna a classe um bean. A maioria das classes em um arquivo de beans já são reconhecidas como beans. A anotação @Named
apenas torna possível referenciar o bean a partir da EL, mais comumente a partir de uma visão JSF.
Nós podemos deixar o CDI escolher um nome para nós, deixando de fora o valor da anotação @Named
:
public @SessionScoped @Named
class ShoppingCart implements Serializable { ... }
O nome padrão vem do nome não-qualificado da classe, descapitalizado; neste caso, shoppingCart
.
Nós já vimos como os qualificadores nos permite escolher entre múltiplas implementações de uma interface durante o desenvolvimento. Mas algumas vezes temos uma interface (ou outro tipo de bean), cuja implementação varia dependendo do ambiente de implantação. Por exemplo, podemos querer usar uma implementação de imitação em um ambiente de teste. Uma alternativa seria declarar a classe de bean com a anotação @Alternative
.
public @Alternative
class MockPaymentProcessor extends PaymentProcessorImpl { ... }
Normalmente anotamos um bean com @Alternative
somente quando existe alguma outra implementação de uma interface que ele implementa (ou de qualquer de seus tipos de bean). Podemos escolher entre as alternativas no momento da implantação selecionando uma alternativa no descritor de implantação do CDI META-INF/beans.xml
dentro do jar ou módulo Java EE que utiliza-o. Diferentes módulos podem especificar que eles usam diferentes alternativos.
We cover alternatives in more detail in Seção 4.7, “Alternativos”.
Você pode estar familiarizado com o uso de interceptadores em EJB 3.0. Em Java EE 6, esta funcionalidade foi generalizada para trabalhar com outros beans gerenciados. Está bem, você não precisa tornar seu bean um EJB apenas para interceptar seus métodos. (Berro). Então, o que CDI tem a oferecer além disso? Bem, bastante realmente. Vamos dar algumas explicações.
A maneira em que interceptadores foram definidos em Java EE 5 não foi muito intuitivo. Era necessário especificar a implementação do interceptador diretamente na implementação do EJB, seja pela anotação @Interceptors
ou no descritor XML. Você pode muito bem apenas colocar o código do interceptador dentro da implementação! Em segundo lugar, a ordem na qual os interceptadores são aplicados é obtida a partir da ordem na qual eles são declarados na anotação ou no descritor XML. Talvez isto não seja tão ruim se você está aplicando os interceptadores a um único bean. Mas, se você está aplicando eles repetidamente, então há uma boa chance de você definir por descuido uma ordem diferente para diferentes beans. Agora isso é um problema.
CDI fornece uma nova abordagem para vincular interceptadores a beans que introduz um nível de indirecionamento (e, portanto, de controle). Nós temos que definir um tipo para vinculação de interceptador que descreve o comportamento implementado pelo interceptador.
Um tipo para vinculação de interceptador é uma anotação definida pelo usuário que é ela mesma anotada com @InterceptorBinding
. Isto nos permite vincular as classes de interceptador a classes de bean com nenhuma dependência direta entre as duas classes.
@InterceptorBinding
@Inherited
@Target( { TYPE, METHOD })
@Retention(RUNTIME)
public @interface Transactional {}
O interceptador que implementa o gerenciamento de transação declara esta anotação:
public @Transactional @Interceptor
class TransactionInterceptor { ... }
Podemos aplicar o interceptador em um bean anotando a classe de bean com o mesmo tipo para vinculação de interceptador.
public @SessionScoped @Transactional
class ShoppingCart implements Serializable { ... }
Observe que ShoppingCart
e TransactionInterceptor
não sabem nada sobre o outro.
Interceptadores são específicos de implantação. (Não precisamos de um TransactionInterceptor
em nossos testes de unidade!) Por padrão, um interceptador está disabilitado. Podemos habilitar um interceptador usando o descritor de implantação CDI META-INF/beans.xml
do jar ou módulo Java EE. Este descritor também é onde especificamos a ordem dos interceptadores.
We'll discuss interceptors, and their cousins, decorators, in Capítulo 9, Interceptadores and Capítulo 10, Decoradores.
Nós já vimos dois tipos de beans: JavaBeans e EJB session beans. Esta é toda a história? Na verdade, é apenas o começo. Vamos explorar as várias categorias de beans que implementações CDI devem suportar sem modificações.
Um managed bean é uma classe Java. O ciclo de vida básico e a semântica de um managed bean são definidos pelo especificação de Managed Beans. Você pode explicitamente declarar um managed bean anotando a classe do bean com @ManagedBean
, mas em CDI você não precisa disto. De acordo com a especificação, o contêiner CDI trata qualquer classe que satisfaz as seguintes condições como um managed bean:
Ela não é uma classe interna não-estática.
Ela é uma classe concreta, ou é anotada com @Decorator
.
Ela não é anotada com uma anotação de definição de componente EJB ou declarada como classe de bean em ejb-jar.xml
.
Ela não implementa javax.enterprise.inject.spi.Extension
.
Ela tem um construtor apropriado—ou seja:
a classe possui um construtor sem parâmetros, ou
a classe declara um construtor anotado com @Inject
.
De acordo com esta definição, entidades JPA são tecnicamente managed beans. No entanto, as entidades possuem ciclo de vida, estado e modelo de identidade próprios e especiais, e são usualmente instanciadas por JPA ou utilizando new
. Portanto, não recomendamos injetar uma classe de entidade diretamente. Recomendamos especialmente não atribuir um escopo que não seja @Dependent
em uma classe de entidade, uma vez que JPA não é capaz de persistir proxies injetados por CDI.
O conjunto de restrições de tipos de bean para um managed bean contém a classe do bean, qualquer superclasse e todas as interfaces que ele implementa diretamente ou indiretamente.
Se um managed bean possui um campo público, ele deve ter o escopo padrão @Dependent
.
Managed beans suportam as chamadas @PostConstruct
e @PreDestroy
de seu ciclo de vida.
Session beans também são, tecnicamente, managed beans. No entanto, uma vez que eles possuem seu próprio e específico ciclo de vida e tiram vantagem de serviços corporativos adicionais, a especificação CDI considera que eles fazem parte de uma categoria diferente de beans.
Session beans pertencem à especificação EJB. Eles possuem um ciclo de vida específico, gerenciamento de estado e o modelo de concorrência é diferente de outros beans geernciados e objetos Java não-gerenciados. Mas session beans participam em CDI apenas como qualquer outro bean. Você pode injetar um session bean dentro de outro session bean, um managed bean dentro de um session bean, um session bean dentro de um managed bean, ter um managed bean observando um evento disparado por um session bean, e assim por diante.
Os massage-driven beans e entity beans são por natureza objetos não-contextuais e não podem ser injetados dentro de outros objetos. No entanto, message-driven beans podem tirar vantagem de algumas funcionadades CDI, como injeção de dependência, interceptadores e decoradores. Na verdade, CDI realizará injeção dentro de qualquer session bean ou message-driven bean, mesmo aqueles que não são instâncias contextuais.
O conjunto irrestrito de tipos de bean para um session bean contém todas as interfaces locais do bean e suas superinterfaces. Se o session bean possui uma classe de bean de visão local, o conjunto irrestrito de tipos de bean contém a classe de bean e todas as superclasses. Além disso, java.lang.Object
é um tipo de bean de todo session bean. Porém, interfaces remotas não são incluídas no conjunto de tipos de bean.
Não existe razão alguma para declarar explicitamente o escopo de um stateless session bean ou singleton session bean. O contêiner EJB controla o ciclo de vida destes beans, de acordo com a semântica da declaração @Stateless
ou @Singleton
. Por outro lado, um stateful session bean pode possuir qualquer escopo.
Stateful session beans podem definir um método de remoção, anotado com @Remove
, que é utilizado pela aplicação para indicar que uma instância deve ser destruída. No entanto, para uma instância contextual do bean—uma instância sob o controle de CDI—este método só pode ser chamado pela aplicação se o bean possuir o escopo @Dependent
. Para beans com outros escopos, a aplicação deve deixar o contêiner destruir o bean.
Então, quando devemos usar um session bean em vez de um simples managed bean? Sempre que precisar dos serviços corporativos avançados oferecidos por EJB, tais como:
gerenciamento de transação e segurança em nível de método,
gerenciamento de concorrência,
passivação em nível de instância para stateful session bean e pooling de instâncias para stateless session beans,
invocação remota ou de serviço web, ou
temporizadores e métodos assíncronos.
Quando não precisamos de nenhuma dessas coisas, um managed bean comum servirá muito bem.
Muitos beans (incluindo qualquer bean @SessionScoped
ou @ApplicationScoped
) estão disponíveis para acesso concorrente. Portanto, o gerenciamento de concorrência oferecido por EJB 3.1 é especialmente útil. A maioria dos beans com escopo de sessão e aplicação devem ser EJBs.
Os beans que mantêm referências a recursos muito pesados, ou tiram muito proveito do estado interno do avançado ciclo de vida gerenciado pelo contêiner, definido pelo modelo stateless/stateful/singleton de EJB, com seu suporte a passivação e pooling de instâncias.
Finalmente, normalmente é óbvio quando gerenciamento de transação a nível de método, segurança a nível de método, temporizadores, métodos remotos ou métodos assíncronos são utilizados.
O ponto que estamos tentando determinar é: usar um session bean quando você precisar dos serviços que ele oferece, não apenas porque você quer usar injeção de dependência, gerenciamento de ciclo de vida, ou interceptadores. Java EE 6 fornece um modelo de programação graduado. É normalmente fácil iniciar com um managed bean habitual e, posteriormente, transformá-lo em um EJB apenas adicionando uma das seguintes anotações: @Stateless
, @Stateful
ou @Singleton
.
Por outro lado, não tenha medo de usar session beans apenas porque você ouviu seus amigos dizer que eles são "pesados". Não é nada mais do que superstição pensar que alguma coisa é "mais pesada" apenas porque é hospedada nativamente dentro do contêiner Java EE, em vez de um contêiner proprietário de beans ou um framework de injeção de dependência que executa como uma camada adicional de ofuscação. E como um princípio geral, você deve desconfiar de pessoas que usam uma terminologia vagamente definida, como "pesado".
Nem tudo que precisa ser injetado pode ser resumido a uma classe de bean sendo instanciada pelo contêiner usando new
. Existe uma abundância de casos onde precisamos de controle adicional. E se precisamos decidir em tempo de execução qual implementação de um dado tipo deve ser instanciado e injetado? E se precisamos injetar um objeto que é obtido ao consultar um serviço ou um recurso transacional, por exemplo, executando uma consulta JPA?
Um método produtor é um método que age como uma fonte de instâncias de bean. A própria declaração do método descreve o bean e o contêiner invoca o método para obter uma instância do bean quando nenhuma instância existe no contexto especificado. Um método produtor permite que a aplicação tome o controle total do processo de instanciação do bean.
Um método produtor é declarado anotando um método de uma classe de bean com a anotação @Produces
.
@ApplicationScoped
public class RandomNumberGenerator {
private Random random = new Random(System.currentTimeMillis());
@Produces @Named @Random int getRandomNumber() {
return random.nextInt(100);
}
}
Não podemos escrever uma classe de bean que é ela própria um número aleatório. Mas podemos certamente escrever um método que retorna um número aleatório. Ao tornar o método um método produtor, permitimos que o valor de retorno do método—neste caso um Integer
—seja injetado. Podemos até mesmo especificar um qualificador—neste caso @Random
, um escopo—que neste caso é por padrão @Dependent
, e um nome EL—que neste caso é por padrão randomNumber
de acordo com a convenção JavaBeans para nome de propriedades. Agora podemos obter um número aleatório em qualquer lugar:
@Inject @Random int randomNumber;
Até mesmo em uma expressão Unified EL:
<p >Your raffle number is #{randomNumber}.</p >
Um método produtor deve ser um método não-abstrato de uma classe de managed bean ou de uma classe de session bean. Um método produtor pode ser estático ou não-estático. Se o bean é um session bean, o método produtor deve ser um método de negócio do EJB ou um método estático da classe do bean.
Os tipos de bean de um método produtor depende do tipo de retorno do método:
Se o tipo de retorno é uma interface, o conjunto ilimitado de tipos de bean contém o tipo de retorno, todas as interfaces estendidas direta ou indiretamente e java.lang.Object
.
Se um tipo tipo de retorno é primitivo ou é um tipo de array Java, o conjunto ilimitado de tipos de bean contém exatamente dois tipos: o tipo de retorno do método e java.lang.Object
.
Se o tipo de retorno é uma classe, o conjunto ilimitado de tipos de bean contém o tipo de retorno, todas superclasses e todas as interfaces implementadas direta ou indiretamente.
Os métodos e campos produtores podem ter um tipo primitivo como bean. Para o propósito de resolver dependências, tipos primitivos são considerados idênticos aos seus correspondentes tipos adaptadores em java.lang
.
If the producer method has method parameters, the container will look for a bean that satisfies the type and qualifiers of each parameter and pass it to the method automatically—another form of dependency injection.
@Produces Set<Roles
> getRoles(User user) {
return user.getRoles();
}
We'll talk much more about producer methods in Capítulo 8, Métodos produtores.
Um campo produtor é uma alternativa mais simples para um método produtor. Um campo produtor é declarado ao anotar um campo de uma classe de bean com a anotação @Produces
—a mesma anotação usada pelos métodos produtores.
public class Shop {
@Produces PaymentProcessor paymentProcessor = ....;
@Produces @Catalog List<Product
> products = ....;
}
As regras para determinação dos tipos de bean de um campo produtor assemelham-se às regras para métodos produtores.
A producer field is really just a shortcut that lets us avoid writing a useless getter method. However, in addition to convenience, producer fields serve a specific purpose as an adaptor for Java EE component environment injection, but to learn more about that, you'll have to wait until Capítulo 14, Recursos do ambiente de componentes Java EE. Because we can't wait to get to work on some examples.