SeamFramework.orgCommunity Documentation

Capítulo 1. Comenzando a escribir Web Beans

1.1. Su primer Web Bean
1.2. ¿Qué es un Web Bean?
1.2.1. Tipos API, tipos de enlace e inyección de dependencia
1.2.2. Tipos de despliegue
1.2.3. Ámbito
1.2.4. Nombres de Web Beans y EL unificado
1.2.5. Tipos de interceptor de enlace
1.3. ¿Qué clase de objetos pueden ser Web Beans?
1.3.1. Web Beans sencillos
1.3.2. Web Beans de empresa
1.3.3. Métodos de productor
1.3.4. endpoints de JMS

Entonces, ¿está preparado para empezar a escribir su primer Web Bean? O quizás está escéptico, preguntándose por qué tipos de arcos le hará ¡saltar la especificación de Web Beans! La buena noticia es que probablemente ya ha escrito y utilizado cientos, quizás miles de Web Beans. Podría no recordar incluso el primer Web Bean que escribió.

Con determinadas excepciones, muy especiales, toda clase de Java con un constructor que no acepte parámetros es un Web Bean. Esto incluye cada JavaBean. Además, cada sesión estilo EJB 3 es un Web Bean. Por supuesto, los JavaBeans y EJB que usted ha escrito a diario no han podido aprovechar los nuevos servicios definidos por la especificación de Web Beans, pero podrá utilizar cada uno de ellos como Web Beans — inyectándolos en otros Web Beans, configurándolos a través de los servicios de configuración, incluso agregándoles interceptores y decoradores — sin tocar su código existente.

Suponga que tenemos dos clases existentes de Java, las cuales hemos estado utilizando por años en varias aplicaciones. La primera clase analiza una cadena en un lista de oraciones:

public class SentenceParser {

    public List<String
> parse(String text) { ... }
}

La segunda clase existente es un bean de front-end sin estado de sesión capaz de traducir oraciones de un idioma a otro:

@Stateless

public class SentenceTranslator implements Translator {
    public String translate(String sentence) { ... }
}

Donde Translator es la interfaz local:

@Local

public interface Translator {
    public String translate(String sentence);
}

Lamentablemente, no tenemos una clase preexistente que traduzca todos los documentos de texto. Entonces, escribamos un Web Bean que realice esta tarea:

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 obtener una instancia de TextTranslator inyectándola en una Web Bean, Servlet o EJB:

@Initializer

public setTextTranslator(TextTranslator textTranslator) {
    this.textTranslator = textTranslator;
}

De modo alterno, podemos obtener una instancia llamando directamente un método del administrador de Web Bean:

TextTranslator tt = manager.getInstanceByType(TextTranslator.class);

Pero espere: ¡TextTranslator no tiene un constructor sin parámetros! ¿Es éste aún un Web Bean? Bueno, una clase que no tiene un constructor sin parámetros aún puede ser un Web Bean si tiene un constructor anotado @Initializer.

Como pudo adivinar, la anotación @Initializer tiene algo que ver con la ¡inyección de dependencia! @Initializer puede aplicarse a un constructor o método de un Web Bean, y pide a un administrador de Bean llamar a ese constructor o método cuando inicia el Web Bean. El administrador de Web Bean inyectará otros Web Beans a los parámetros del constructor o método.

En el momento de inicialización, el administrador de Web Bean debe confirmar que exista exactamente un Web Bean que complete cada punto de inyección. En nuestro ejemplo, si no estaba disponible ninguna implementación de Translator — si el EJB de SentenceTranslator no estaba desplegado — el administrador de Web Bean produciría una UnsatisfiedDependencyException. Si más de una implementación de Translator estuviera disponible, el administrador de Web Bean produciría una AmbiguousDependencyException.

Entonces, ¿qué es, exactamente un Web Bean?

Un Web Bean es una clase de aplicación que contiene lógica de negocios. Un Web Bean puede llamarse directamente desde el código de Java, o invocarse a través de Unified EL. Un Web Bean puede acceder recursos transaccionales. Las dependencias entre Web Beans son manejadas automáticamente por el administrador de Web Bean. La mayoría de Web Beans son con estado y contextuales. El ciclo de vida de un Web Bean siempre es manejado por el administrador de Web Bean.

Volvamos atrás por un segundo. ¿Qué significa "contextual"? Puesto que Web Beans puede tener estados, es importante saber qué instancia de bean se tiene. A diferencia de un modelo de componente sin estado (por ejemplo, beans sin estado de sesión) o un modelo de componente singleton (como servlets, o beans singleton), clientes diferentes de un Web Bean ven el Web Bean en estados diferentes. El estado cliente-visible depende de la instancia de Web Bean a la que se refiere el cliente.

No obstante, como un modelo sin estado o un modelo singleton, pero a diferencia de los beans con estado de sesión, el cliente no controla el ciclo de vida de la instancia explícitamente creando y destruyéndolo. En su lugar, el ámbito del Web Bean determina:

Para un subproceso dado en una aplicación de Web Beans, puede haber un contexto activo asociado con el ámbito del Web Bean. Este contexto puede ser único para el subproceso (por ejemplo, si el Web Bean tiene un ámbito de petición), o puede compartirse con algunos subprocesos (por ejemplo, si el Web Bean tiene un ámbito de sesión) o incluso con todos los otros subprocesos (si es el ámbito de la aplicación).

Los clientes (por ejemplo, otros Web Beans) ejecutando en el mismo contexto verán la misma instancia del Web Bean. Pero los clientes en un contexto diferente verán una instancia diferente.

Una gran ventaja del modelo contextual es que permite a los Web Beans con estado ser tratados como ¡servicios! El cliente no necesita preocuparse por manejar el ciclo de vida del Web Bean que está utilizando, ni necesita saber qué ciclo de vida es. Los Web Beans interactúan pasando mensajes, y las implementaciones del Web Bean definen el ciclo de vida de su propio estado. Los Web Beans están en parejas sueltas porque:

Podemos remplazar un Web Bean por un Web Bean diferente que implemente la misma API y tenga un ciclo de vida diferente (un ámbito diferente) sin afectar la otra implementación de Web Bean. De hecho, Web Beans define una facilidad altamente desarrollada para anular las implementaciones de Web Bean en el momento del despliegue, como también ver en Sección 4.2, “Tipos de despliegue”.

Observe que todos los clientes de una Web Bean son Web Beans. Otros objetos tales como Servlets o Message-Driven Beans — los cuales son por naturaleza no inyectables, objetos contextuales — también pueden obtener referencias a Web Beans por inyección.

Más formalmente, de acuerdo con la especificación:

Un Web Bean comprende:

  • Conjunto (no vacío) de Tipos API

  • Un conjunto (no vacío) de tipos de anotación

  • Un ámbito

  • Un tipo de despliegue

  • Alternativamente, un nombre de Web Bean

  • Un conjunto de tipos de interceptor de enlace

  • Una implementación de Web Bean

Veamos lo que significan algunos de estos términos, para el desarrollador de Web Bean.

Los Web Beans suelen adquirir referencias a otros Web Beans a través de la inyección de dependencia. Cualquier atributo inyectado especifica un "contrato" que debe cumplir el Web Bean que va a ser inyectado. El contrato es:

Una API es una clase o interfaz de usuario-definida. (Si el Web Bean es un bean EJB de sesión, el tipo API es la vista de bean de interfaz @Local o de clase). Un tipo de enlace representa alguna semántica visible de cliente cumplida por algunas implementaciones de API y no por otras.

Los tipos de enlace están representados por anotaciones de usuario-definidas hechas por ellas mismas @BindingType. Por ejemplo, el siguiente punto de inyección tiene un tipo de PaymentProcessor de API y un tipo de enlace @CreditCard:

@CreditCard PaymentProcessor paymentProcessor

Si no está explícito ningún tipo de enlace en el punto de inyección, se asumirá el tipo de enlace predeterminado @Current.

Para cada punto de inyección, el administrador de Web Bean busca un Web Bean que cumpla el contrato (implemente el API, y tenga todos los tipos de enlace), e inyecta ese Web Bean.

El siguiente Web Bean tiene el tipo de enlace @CreditCard e implementa el tipo API PaymentProcessor. Podría por lo tanto ser inyectado en el punto de inyección de ejemplo:

@CreditCard

public class CreditCardPaymentProcessor 
    implements PaymentProcessor { ... }

Si un Web Bean no especifica explícitamente un conjunto de tipos de enlace, tiene exactamente un tipo de enlace: el tipo de enlace predeterminado @Current.

Web Beans define un algoritmo de resolución altamente desarrollado e intuitivo que ayuda al contenedor a decidir qué debe hacer si hay uno más de un Web Beans que cumpla un contrato determinado. Veremos esta información en detalle en Capítulo 4, Inyección de dependencia.

Ya hemos visto que JavaBeans, EJB y algunas otras clases de Java pueden ser Web Beans. Pero, exactamente, ¿qué clase de objetos son los Web Beans?

La especificación dice que todos los beans de sesión estilo EJB 3- y singleton son empresariales. Los mensajes de beans no son Web Beans — porque no están diseñados para ser inyectados en otros objetos — pero pueden aprovechar la mayoría de las funcionalidades de los Web Beans, incluyendo la inyección de dependencia y los interceptores.

No toda interfaz local de un Web Bean empresarial tiene un parámetro de tipo comodín o tipo variable, cada una de sus superinterfaces, es un tipo API del Web Bean de empresa. Si el bean EJB tiene una vista local de clase de bean, la clase de bean, y cada una de sus superclases, también es un tipo API.

Los beans con estado de sesión deben declarar un método de eliminación sin parámetros o un método de eliminación anotado @Destructor. El administrador de Web Bean llama a este método para destruir la instancia de bean con estado de sesión al final del ciclo de vida. Este método se llama el métododestructor del Web Bean empresarial.

@Stateful @SessionScoped

public class ShoppingCart {
    ...
    
    @Remove
    public void destroy() {}
}

¿Entonces deberíamos utilizar un Web Bean empresarial en lugar del Web Bean sencillo? Bueno, cada vez que necesitemos los servicios de empresa avanzados ofrecidos por EJB, tales como:

deberíamos utilizar un Web Bean empresarial. Cuando no necesitemos ninguna de estas cosas, bastará con un Web Bean sencillo.

Muchos Web Beans (incluyendo toda sesión o ámbito de aplicación Web Bean) están disponibles para acceso concurrente. Por lo tanto, la administración de concurrencia proporcionada por EJB3.1 es especialmente útil. La mayor parte de la sesión y el ámbito de la aplicación WebBeans debe ser EJB.

Los Web Beans que guardan referencias a recursos pesados, o mantienen un montón de estado interno se benefician del ciclo de vida de contenedor avanzado - administrado definido por el modelo EJB @Stateless/@Stateful/@Singleton, con el soporte para pasivación y grupo de instancia.

Por último, suele ser evidente cuando la administración de transacción nivel-método, seguridad nivel-método, temporizadores o métodos remotos o asíncronos se requieren.

Suele ser fácil iniciar con un Web Bean sencillo y luego cambiar a un EJB, con sólo añadir una anotación: @Stateless, @Stateful o @Singleton.

Un método de productor es un método llamado por el administrador de Web Bean para obtener una instancia del Web Bean cuando no exista en el actual contexto. Un método de productor permite a la aplicación tomar el control total del proceso de iniciación, en lugar de dejar la instanciación al administrador de Web Bean. Por ejemplo:

@ApplicationScoped

public class Generator {
    private Random random = new Random( System.currentTimeMillis() );
    
    @Produces @Random int next() {
        return random.nextInt(100);
    }
}

El resultado de un método de productor es inyectado como cualquier otro Web Bean.

@Random int randomNumber

El método de tipo de retorno y todas las interfaces que extiende/implementa directa o indirectamente son tipos API del método del productor. Si el tipo de retorno es una clase, todas las superclases tienen también tipos API.

Algunos métodos de productor retornan objetos que requieren destrucción explícita:

@Produces @RequestScoped Connection connect(User user) {

    return createConnection( user.getId(), user.getPassword() );
}

Estos métodos de productor pueden definir métodos desechables:

void close(@Disposes Connection connection) {

    connection.close();
}

Este método desechable es llamado automáticamente por el administrador de Web Bean al final de la petición.

Hablaremos mucho más acerca de métodos del productor en Capítulo 6, Métodos de productor.