SeamFramework.orgCommunity Documentation
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:
el ciclo de vida de cada instancia del Web Bean y
los clientes que comparten una referencia a una instancia determinada del Web Bean.
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:
interactúan a través de API públicas bien-definidas
sus ciclos de vida son completamente dispares
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:
Un tipo API, junto con
un conjunto de tipos de enlace.
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.
Los tipos de despliegue nos permiten clasificar nuestros Web Beans por escenario de despliegue. Un tipo de despliegue es una anotación que representa un escenario de despliegue determinado, por ejemplo, @Mock
, @Staging
o @AustralianTaxLaw
. Aplicamos la anotación a Web Beans la cual debe ser desplegada en ese escenario. Un tipo de despliegue permite a todo un conjunto de Web Beans ser condicionalmente desplegado, con sólo una línea de configuración.
Muchos Web Beans sólo utilizan el tipo de despliegue predeterminado @Production
, en cuyo caso no se necesita especificar ningún tipo de despliegue. Todos los tres Web Bean en nuestro ejemplo tienen un tipo de despliegue @Production
.
En un entorno de prueba, podríamos desear remplazar el SentenceTranslator
Web Bean por un "mock object":
@Mock
public class MockSentenceTranslator implements Translator {
public String translate(String sentence) {
return "Lorem ipsum dolor sit amet";
}
}
Habilitaremos un tipo de despliegue @Mock
en nuestro entorno de prueba, para indicar que MockSentenceTranslator
y cualquier otro Web Bean anotado @Mock
debería utilizarse.
Hablaremos más acerca de esta característica única y poderosa en Sección 4.2, “Tipos de despliegue”.
El ámbito define el ciclo de vida y visibilidad de instancias del Web Bean. El modelo de contexto de Web Beans es extensible, acomodando los ámbitos arbitrarios. Sin embargo, ciertos ámbitos importantes son incorporados en la especificación y provistos por el administrador de Web Bean. Un ámbito está representado por un tipo de anotación.
Por ejemplo, cualquier aplicación de red puede tener una sesión en ámbito de Web Beans:
@SessionScoped
public class ShoppingCart { ... }
Una instancia de una sesión en ámbito Web Bean está vinculada a una sesión de usuario y es compartida por todos los solicitantes que ejecutan en el contexto de esa sesión.
Por defecto, Web Beans pertenece a un ámbito especial llamado el ámbito seudo dependiente. Web Beans con este ámbito son objetos puros dependientes del objeto en el que son inyectados y su ciclo de vida está vinculado al ciclo de vida del objeto.
Hablaremos más acerca de ámbitos en Capítulo 5, Ámbitos y contextos.
Un Web Bean puede tener un nombre, que le permita ser utilizado en expresiones EL unificadas. Es fácil especificar el nombre de un Web Bean:
@SessionScoped @Named("cart")
public class ShoppingCart { ... }
Ahora podemos utilizar el Web Bean en cualquier página JSF o JSP:
<h:dataTable value="#{cart.lineItems}" var="item"> .... </h:dataTable >
Es aún más fácil dejar el nombre predeterminado por el administrador de Web Bean:
@SessionScoped @Named
public class ShoppingCart { ... }
En este caso, el nombre predetermina al shoppingCart
el nombre de clase no calificado, con el primer caracter cambiado a minúsculas.
Web Beans admite la funcionalidad de interceptor definida por el EJB 3, no sólo por beans EJB, sino también por clases de Java comunes. Además, Web Beans proporciona un nuevo método para enlazar interceptores de enlace a beans EJB y otras Web Beans.
Es posible especificar directamente la clase de interceptor a través de la anotación @Interceptors
:
@SessionScoped
@Interceptors(TransactionInterceptor.class)
public class ShoppingCart { ... }
Sin embargo, no es más elegante y mejor práctica, llevar indirectamente al interceptor enlazando a través de un tipo de interceptor de enlace:
@SessionScoped @Transactional
public class ShoppingCart { ... }
Hablaremos acerca de los interceptores y decoradores de Web Beans en Capítulo 7, Interceptores y Capítulo 8, Decoradores.
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 de Web Beans dice que una clase de Java concreta es un Web Bean sencillo si:
no es un componente de contenedor EE - administrado, como un EJB, un Servlet o una entidad JPA,
no es una clase interna no estática,
no es un tipo en parámetros, y
tiene un constructor sin parámetros o un constructor @Initializer
anotado.
Entonces, casi cada JavaBean es un Web Bean sencillo
Cada interfaz implementada directamente o indirectamente por un Web Bean sencillo es un tipo API de un Web Bean sencillo. La clase y superclase también son tipos API.
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:
administración de transacciones nivel-método y seguridad,
gestión de concurrencia,
pasivación de nivel-instancia para beans con estado de sesión y grupo-instancia para beans sin estado de sesión
invocación de servicio de red y remoto
temporizadores y métodos asíncronos,
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.
Por último, una cola o tópico JMS puede ser un Web Bean. Web Beans libera al desarrollador del tedio de manejar los ciclos de vida de todos los objetos JMS requeridos para enviar mensajes a colas y tópicos. Discutiremos sobre endpoints de JMS en Sección 13.4, “endpoints JMS”.