SeamFramework.orgCommunity Documentation
Então você está interessado em começar a escrever o seu primeiro Web Bean? Ou talvez você é cético, imaginando que tipos de hoops a especificação Web Beans fará com que você passe! A boa notícia é que você provavelmente já escreveu e utilizou centenas, talvez milhares de Web Beans. Você pode até não se lembrar do primeiro Web Bean que escreveu.
Com certeza, com raras exceções especiais, toda classe Java com um construtor sem parâmetros é um Web Bean. Isso inclui todos os JavaBean. Além disso, todo session bean no estilo EJB 3 é um Web Bean. Claro, JavaBeans e EJBs que você tem escrito todos os dias, não tem sido capazes de aproveitar os novos serviços definidos pela especificação Web Beans, mas você será capaz de usar cada um deles como Web Beans - injetando-os em outros Web Beans, configurando-os através da Web Beans XML configuration facility, e até acrescentando interceptadores e decoradores sem tocar o seu código existente.
Suponha que temos duas classes Java existentes, que temos utilizado por anos em várias aplicações. A primeira classe faz a divisão (parse) de uma string em uma lista de sentenças:
public class SentenceParser {
public List<String
> parse(String text) { ... }
}
A segunda classe existente é um stateless session bean de fachada (front-end) para um sistema externo que é capaz de traduzir frases de uma língua para outra:
@Stateless
public class SentenceTranslator implements Translator {
public String translate(String sentence) { ... }
}
Onde Translator
é a interface local:
@Local
public interface Translator {
public String translate(String sentence);
}
Infelizmente, não temos uma classe pré-existente que traduz todo o texto de documentos. Então vamos escrever um Web Bean que faz este trabalho:
public class TextTranslator {
private SentenceParser sentenceParser;
private Translator sentenceTranslator;
@Initializer
TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator) {
this.sentenceParser = sentenceParser;
this.sentenceTranslator = sentenceTranslator;
}
public String translate(String text) {
StringBuilder sb = new StringBuilder();
for (String sentence: sentenceParser.parse(text)) {
sb.append(sentenceTranslator.translate(sentence));
}
return sb.toString();
}
}
Podemos obter uma instância de TextTranslator
injetando-a em um Web Bean, Servlet ou EJB:
@Initializer
public setTextTranslator(TextTranslator textTranslator) {
this.textTranslator = textTranslator;
}
Alternativamente, nós podemos obter uma instância invocando diretamente o método do gerenciador do Web Bean:
TextTranslator tt = manager.getInstanceByType(TextTranslator.class);
Mas espere: TextTranslator
não tem um construtor sem parâmetros! É ainda um Web Bean? Bem, uma classe que não tem um construtor sem parâmetros ainda pode ser um Web Bean, se tiver um construtor anotado com @Initializer
.
As you've guessed, the @Initializer
annotation has something to do with dependency injection! @Initializer
may be applied to a constructor or method of a Web Bean, and tells the Web Bean manager to call that constructor or method when instantiating the Web Bean. The Web Bean manager will inject other Web Beans to the parameters of the constructor or method.
At system initialization time, the Web Bean manager must validate that exactly one Web Bean exists which satisfies each injection point. In our example, if no implementation of Translator
available if the SentenceTranslator
EJB was not deployed the Web Bean manager would throw an UnsatisfiedDependencyException
. If more than one implementation of Translator
was available, the Web Bean manager would throw an AmbiguousDependencyException
.
Então, o que, exatamente, é um Web Bean?
A Web Bean is an application class that contains business logic. A Web Bean may be called directly from Java code, or it may be invoked via Unified EL. A Web Bean may access transactional resources. Dependencies between Web Beans are managed automatically by the Web Bean manager. Most Web Beans are stateful and contextual. The lifecycle of a Web Bean is always managed by the Web Bean manager.
Let's back up a second. What does it really mean to be "contextual"? Since Web Beans may be stateful, it matters which bean instance I have. Unlike a stateless component model (for example, stateless session beans) or a singleton component model (such as servlets, or singleton beans), different clients of a Web Bean see the Web Bean in different states. The client-visible state depends upon which instance of the Web Bean the client has a reference to.
No entanto, como o modelo stateless ou singleton, mas ao contrário dos stateful session beans, o cliente não controla o ciclo de vida da instância por explicitamente criar e destruí-lo. Em vez disso, o escopo do Web Bean determina:
o ciclo de vida de cada instância do Web Bean e
que os clientes compartilham uma referência a uma instância específica do Web Bean.
For a given thread in a Web Beans application, there may be an active context associated with the scope of the Web Bean. This context may be unique to the thread (for example, if the Web Bean is request scoped), or it may be shared with certain other threads (for example, if the Web Bean is session scoped) or even all other threads (if it is application scoped).
Os clientes (por exemplo, outros Web Beans) executam no mesmo contexto verão a mesma instância do Web Bean. Mas os clientes em um contexto diferente verão uma outra instância.
One great advantage of the contextual model is that it allows stateful Web Beans to be treated like services! The client need not concern itself with managing the lifecycle of the Web Bean it is using, nor does it even need to know what that lifecyle is. Web Beans interact by passing messages, and the Web Bean implementations define the lifecycle of their own state. The Web Beans are loosely coupled because:
ele interagem por uma API pública bem definida
seus ciclos de vida são completamente desacoplados
We can replace one Web Bean with a different Web Bean that implements the same API and has a different lifecycle (a different scope) without affecting the other Web Bean implementation. In fact, Web Beans defines a sophisticated facility for overriding Web Bean implementations at deployment time, as we will see in Seção 4.2, “Tipo de deploy”.
Note que nem todos os clientes de um Web Bean são Web Beans. Outros objetos, tais como Servlets ou Message-Driven Beans que são, por natureza, não injetável, objetos contextuais podem também obter referências a Web Beans por injeção.
Chega de mão abanando. Mais formalmente, de acordo com a especificação:
Um Web Bean compreende:
Um conjunto (não vazio) de tipos de API (API types)
Um conjunto (não vazio) de tipos de anotações de binding
Um escopo
Um tipo de publicação (deployment type)
Opcionalmente, um nome Web Bean
Um conjunto de tipos de interceptor binding
A implementação de Web Bean
Vamos ver o que alguns destes termos significam, para o desenvolvedor Web Bean.
Web Beans usually acquire references to other Web Beans via dependency injection. Any injected attribute specifies a "contract" that must be satisfied by the Web Bean to be injected. The contract is:
um tipo de API, juntamente com
um conjunto de tipos de binding
An API is a user-defined class or interface. (If the Web Bean is an EJB session bean, the API type is the @Local
interface or bean-class local view). A binding type represents some client-visible semantic that is satisfied by some implementations of the API and not by others.
Binding types are represented by user-defined annotations that are themselves annotated @BindingType
. For example, the following injection point has API type PaymentProcessor
and binding type @CreditCard
:
@CreditCard PaymentProcessor paymentProcessor
If no binding type is explicitly specified at an injection point, the default binding type @Current
is assumed.
For each injection point, the Web Bean manager searches for a Web Bean which satisfies the contract (implements the API, and has all the binding types), and injects that Web Bean.
The following Web Bean has the binding type @CreditCard
and implements the API type PaymentProcessor
. It could therefore be injected to the example injection point:
@CreditCard
public class CreditCardPaymentProcessor
implements PaymentProcessor { ... }
If a Web Bean does not explicitly specify a set of binding types, it has exactly one binding type: the default binding type @Current
.
Web Beans defines a sophisticated but intuitive resolution algorithm that helps the container decide what to do if there is more than one Web Bean that satisfies a particular contract. We'll get into the details in Capítulo 4, Injeção de Dependências.
Deployment types let us classify our Web Beans by deployment scenario. A deployment type is an annotation that represents a particular deployment scenario, for example @Mock
, @Staging
or @AustralianTaxLaw
. We apply the annotation to Web Beans which should be deployed in that scenario. A deployment type allows a whole set of Web Beans to be conditionally deployed, with a just single line of configuration.
Many Web Beans just use the default deployment type @Production
, in which case no deployment type need be explicitly specified. All three Web Bean in our example have the deployment type @Production
.
In a testing environment, we might want to replace the SentenceTranslator
Web Bean with a "mock object":
@Mock
public class MockSentenceTranslator implements Translator {
public String translate(String sentence) {
return "Lorem ipsum dolor sit amet";
}
}
We would enable the deployment type @Mock
in our testing environment, to indicate that MockSentenceTranslator
and any other Web Bean annotated @Mock
should be used.
Iremos falar mais sobre essa única e poderosa funcionalidade em Seção 4.2, “Tipo de deploy”.
The scope defines the lifecycle and visibility of instances of the Web Bean. The Web Beans context model is extensible, accommodating arbitrary scopes. However, certain important scopes are built-in to the specification, and provided by the Web Bean manager. A scope is represented by an annotation type.
Por exemplo, qualquer aplicação web pode ter Web Beans com escopo de sessão (session scoped):
@SessionScoped
public class ShoppingCart { ... }
An instance of a session scoped Web Bean is bound to a user session and is shared by all requests that execute in the context of that session.
Por padrão, os Web Beans pertencem a um escopo especial chamado de dependent pseudo-scope. Web Beans com este escopo são objetos puramente dependentes do objeto em que são injetados, e seu ciclo de vida está atrelado ao ciclo de vida desse objeto.
Falaremos mais sobre escopos no Capítulo 5, Escopos e contextos.
Um Web Bean pode ter um name, que lhe permite ser utilizado em expressões da Unified EL. É fácil especificar o nome de um Web Bean:
@SessionScoped @Named("cart")
public class ShoppingCart { ... }
Agora, podemos facilmente utilizar o Web Bean em qualquer página JSF ou JSP:
<h:dataTable value="#{cart.lineItems}" var="item"> .... </h:dataTable >
É ainda mais fácil, deixar o nome ser atribuído pelo gerenciador do Web Bean:
@SessionScoped @Named
public class ShoppingCart { ... }
Neste caso, o nome fica shoppingCart
o nome da classe não qualificado (unqualified class name), com o primeiro caractere alterado para minúsculas.
Web Beans suporta a funcionalidade de interceptador (interceptor) definida pela EJB 3, não apenas para beans EJB , mas também para classes Java simples (plain Java classes). Além disso, a Web Beans oferece uma nova abordagem para vincular interceptores (binding interceptors) para beans EJB e outros Web Beans.
It remains possible to directly specify the interceptor class via use of the @Interceptors
annotation:
@SessionScoped
@Interceptors(TransactionInterceptor.class)
public class ShoppingCart { ... }
No entanto, é mais elegante, e uma melhor prática, indirecionar o binding do interceptador através de um interceptor binding type:
@SessionScoped @Transactional
public class ShoppingCart { ... }
We'll discuss Web Beans interceptors and decorators in Capítulo 7, Interceptadores and Capítulo 8, Decoradores.
We've already seen that JavaBeans, EJBs and some other Java classes can be Web Beans. But exactly what kinds of objects are Web Beans?
A especificação de Web Beans diz que uma classe Java concreta é um Web Bean simples se:
não é um componente gerenciado pelo container, como um EJB, um Servlet ou uma entidade da JPA,
it is not a non-static static inner class,
não é um tipo parametrizado, e
que tem um construtor sem parâmetros, ou um construtor anotado com @Initializer
.
Assim, quase todo JavaBean é um Web Bean simples.
Every interface implemented directly or indirectly by a simple Web Bean is an API type of the simple Web Bean. The class and its superclasses are also API types.
The specification says that all EJB 3-style session and singleton beans are enterprise Web Beans. Message driven beans are not Web Beans since they are not intended to be injected into other objects but they can take advantage of most of the functionality of Web Beans, including dependency injection and interceptors.
Every local interface of an enterprise Web Bean that does not have a wildcard type parameter or type variable, and every one of its superinterfaces, is an API type of the enterprise Web Bean. If the EJB bean has a bean class local view, the bean class, and every one of its superclasses, is also an API type.
Stateful session beans should declare a remove method with no parameters or a remove method annotated @Destructor
. The Web Bean manager calls this method to destroy the stateful session bean instance at the end of its lifecycle. This method is called the destructor method of the enterprise Web Bean.
@Stateful @SessionScoped
public class ShoppingCart {
...
@Remove
public void destroy() {}
}
Então, quando deveremos usar Web Bean corporativo (enterprise) em vez de um simples Web Bean? Bem, sempre que tivermos a necessidade de serviços corporatvios (enterprise) avançados oferecidos pelo EJB, tais como:
gerenciamento de transações e segurança em nível de método,
gerenciamento de concorrência,
instance-level passivation for stateful session beans and instance-pooling for stateless session beans,
remoto e invocação de web service, e
temporizadores (timers) e métodos assíncronos
devemos utilizar um Web Bean corporativo (enterprise). Quando não precisamos de nenhuma destas coisas, um Web Bean simples vai servir muito bem.
Muitos Web Beans (incluindo qualquer Web Bean em escopo de sessão ou de aplicação) estão disponíveis para acesso concorrente. Por isso, o gerenciamento de concorrência fornecida pelo EJB 3.1 é especialmente útil. A maioria dos Web Beans em escopo de sessão e aplicação devem ser EJBs.
Web Beans which hold references to heavy-weight resources, or hold a lot of internal state benefit from the advanced container-managed lifecycle defined by the EJB @Stateless
/@Stateful
/@Singleton
model, with its support for passivation and instance pooling.
Por último, isso normalmente é óbvio quando gerenciamento de transações e segurança em nível de método, temporizadores, métodos remotos ou assíncronos são necessários.
It's usually easy to start with simple Web Bean, and then turn it into an EJB, just by adding an annotation: @Stateless
, @Stateful
or @Singleton
.
A producer method is a method that is called by the Web Bean manager to obtain an instance of the Web Bean when no instance exists in the current context. A producer method lets the application take full control of the instantiation process, instead of leaving instantiation to the Web Bean manager. For example:
@ApplicationScoped
public class Generator {
private Random random = new Random( System.currentTimeMillis() );
@Produces @Random int next() {
return random.nextInt(100);
}
}
O resultado do método produtor é injetado como qualquer outro Web Bean.
@Random int randomNumber
The method return type and all interfaces it extends/implements directly or indirectly are API types of the producer method. If the return type is a class, all superclasses are also API types.
Alguns métodos produtores retornam objetos que exigem destruição explícita :
@Produces @RequestScoped Connection connect(User user) {
return createConnection( user.getId(), user.getPassword() );
}
Estes métodos produtores podem definir métodos eliminação (disposal methods):
void close(@Disposes Connection connection) {
connection.close();
}
Este método de eliminação (disposal method) é chamado automaticamente pelo gerenciador do Web Bean no final da requisição.
Falaremos mais sobre métodos produtores no Capítulo 6, Métodos produtores.
Finally, a JMS queue or topic can be a Web Bean. Web Beans relieves the developer from the tedium of managing the lifecycles of all the various JMS objects required to send messages to queues and topics. We'll discuss JMS endpoints in Seção 13.4, “Endpoints JMS”.