SeamFramework.orgCommunity Documentation

Capítulo 1. Introdução a Web Beans

1.1. Seu primeiro Web Bean
1.2. O que é um Web Bean?
1.2.1. Tipos de API, tipos de binding e injeção de dependências
1.2.2. Tipos de publicação (deployment types)
1.2.3. Escopo
1.2.4. Nomes Web Beans e Unified EL
1.2.5. Tipos de interceptor binding
1.3. Que tipos de objetos podem ser Web Beans?
1.3.1. Web Beans Simples
1.3.2. Web Beans corporativos (Enterprise Web Beans)
1.3.3. Métodos produtores (producer methods)
1.3.4. JMS endpoints

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:

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:

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:

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.

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?

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:

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.