Resumen Este artículo discutirá con usted cómo combinar el poder de las anotaciones y aspectos para proporcionar servicios declarativos a las empresas de una manera compatible con EJB 3.0 mientras proporciona independencia del contenedor.
1. Introducción
En nuestra búsqueda conjunta de formas de mejorar aún más el rendimiento de producción del desarrollo de software, nosotros, como miembros de la comunidad Java, generalmente recurrimos a J2EE para proporcionar problemas técnicos más desafiantes en el desarrollo empresarial, como soluciones de gestión de transacciones distribuidas, concurrencia y distribución de objetos. La ideología guía detrás de esto (proveedores de servidores de aplicaciones pueden implementar estos servicios empresariales complejos y equilibrados por los desarrolladores comerciales, es una buena idea. J2EE, específicamente EJB, ha proporcionado con éxito una plataforma en la que se construyen aplicaciones Java Enterprise.
Parte de este éxito se debe a la capacidad de realizar una programación declarativa, una forma de desarrollar un programa, en el que puede declarar servicios de infraestructura en lugar de codificar explícitamente con la lógica comercial para que el código se extienda por todas partes. EJB ha demostrado el valor de este enfoque de programación, al permitir que los problemas empresariales, como las transacciones y la seguridad, se declaren con un descriptor de publicación y manejen un contenedor.
Sin embargo, en los últimos años, cada vez más desarrolladores se han dado cuenta de que EJB se presenta muchos desafíos nuevos en la productividad de un equipo: cada EJB debe ir acompañado de múltiples interfaces, con una descripción de la publicación de descriptores, a través de JNDI, etc. Las pruebas unitarias en EJB fuera del contenedor también trae dificultades adicionales.
Tenga en cuenta que para leer este artículo, debe tener las siguientes herramientas:
· Java 2 SDK 1.5
· Maven 2.0 beta 2
El objetivo de EJB 3.0 es facilitar el desarrollo empresarial en los siguientes aspectos:
· Implementar solicitudes declarativas de servicios empresariales mediante la introducción de anotaciones de metadatos
· Implementar la inyección de dependencia/recursos a través de la anotación
· Implementar el desacoplamiento de frijoles empresariales e interfaces específicas de EJB
· Simplificación del almacenamiento continuo a través de la asignación ligera de objetos relacionales
Esto es como una brisa de primavera para los desarrolladores de EJB: han estado trabajando duro para desarrollar, probar y mantener EJB. Ahora es fácil escribir un frijol empresarial usando EJB 3.0, al igual que crear un POJO (objeto Java tradicional) con anotaciones específicas para marcarlo como un EJB y solicitar servicios empresariales. Aquí hay un ejemplo de EJB en EJB 3.0 Public Draft:
@stateful
clase pública Cartbean implementa compras de compras
{
Total flotante privado;
Códigos de productos de vectores privados;
public int someshoppingMethod () {...};
...
}
La declaración EJB 3.0 esencialmente establece que lo que los desarrolladores necesitan no es una solución de peso pesado, "una versión que satisface todo", sino una solución liviana y fácil de usar, que proporciona a los desarrolladores una cierta gama de servicios empresariales. Con este fin, uno de los métodos más importantes proporcionados por EJB 3.0 es desacoplar los frijoles empresariales y las API EJB. Y esta solución también trae derivados interesantes: EJB ahora puede ejecutarse no solo en diferentes contenedores EJB, sino también dentro de cualquier marco de aplicación: estos marcos deben poder reconocer EJB 3.0 (JSR 220) y una anotación normal para declarar servicios empresariales (JSR 250) .
Este artículo no proporciona una exploración en profundidad de la programación declarativa, EJBS, aspectos o anotaciones. En cambio, simplemente analice las interrelaciones entre estas tecnologías y discuta cómo combinarlas de una nueva manera para simplificar el desarrollo de aplicaciones.
En este artículo, aprenderá cómo escribir un frijol compatible con EJB 3.0 y crear varios aspectos simples para que sea de manejo de transacciones declarativas, seguridad e inyección de recursos. Espero que puedas beneficiarte de este ejercicio:
· Tres aplicaciones prácticas en aprendizaje (inyección de dependencia, seguridad y transacción).
· Familiarizado con EJB 3.0 y las ideas detrás de esto.
Reconozca cómo implementar el desacoplamiento de EJB de API específicas para permitir que los servicios compatibles con EJB 3.0 se implementen con peso ligero en lugar de lo proporcionado solo por EJB.
2. Ejemplo de orden de aplicación de aplicación
A lo largo de la discusión, aprenderá sobre una implementación de un sistema de pedidos de vuelo, que utiliza aspectos y anotaciones para implementar la inyección de dependencia, la seguridad y la gestión de transacciones. La aplicación realiza solo dos funciones: permite a los usuarios buscar vuelos (Figura 1) y luego pedir un viaje (Figura 2). Ambas operaciones se procesarán de forma segura para permitir que solo los usuarios identificados los realicen. Además, dado que la operación "Orden de viaje" implica ordenar dos vuelos (vuelos fuera y de regreso), la operación debe crearse como transaccional, por ejemplo, ambos pedidos tendrán éxito o fallarán como una unidad de trabajo.
Figura 1. Consulta de vuelo: Primero, los usuarios buscan vuelos que cumplan con sus criterios especificados.
Figura 2. Pedido de vuelo: a continuación, el usuario ordena un vuelo de salida y un vuelo de regreso. Ambas órdenes tienen éxito o fallan.
Esta simple aplicación web contiene varios servlets, una apariencia de servicio y una capa DAO (ver Figura 3).
Las preocupaciones transversales como la configuración de recursos, la seguridad y la gestión de transacciones serán proporcionadas por aspectos (implementados con SuppeJ 1.5 m3) para implementar el comportamiento de inyección declarado en las anotaciones de Java 5.
Figura 3. Arquitectura del sistema de pedidos de vuelo: este sistema de pedidos de vuelo consta de tres componentes principales: se unen para completar las solicitudes de los usuarios. 3. Inyección de recursos
El borrador de EJB 3.0 Declaración permite que los recursos se declaren a través de la anotación @Resource (esta decisión se define en el borrador de la declaración de anotación ordinaria) e inyectado en su EJB por contenedor. La inyección de dependencia es una técnica: utilizando esta técnica, una entidad fuera de un objeto en lugar de una entidad creada explícitamente para ese objeto puede proporcionar (inyectar) la dependencia de un objeto. A veces se describe como un principio de Hollywood, que bromea como "No nos llames, te llamaremos".
Tome la clase TravelAgencyServiceImpl como ejemplo: para almacenar continuamente algunos datos, esta clase necesita encontrar una implementación de la interfaz IFLightDAO. Tradicionalmente, esto se logra a través de una fábrica, singleton, localizador de servicios o alguna otra solución personalizada. Entre ellos, una posible solución se ve así:
Clase pública TravelAgencyServiceImpl implementa ITTRAVELAGENCYService
{
Public Iflightdao Flightdao;
Public TravelAgencyServiceImpl ()
{Flightdao = FlightDaOfactory.GetInstance (). GetFlightDao ();
Public void booktrip (Long OutboundFlightid, Long Returnflightid, int Seats)
lanza inválida de la concepción
{
Reserveseats (Outboundflightid, asientos);
Reserveseats (returnflightid, asientos);
}
}
Ha visto que esta implementación implica la creación de una clase de fábrica específica: es probable que lea la información de configuración almacenada en algún lugar para comprender cómo se creará la implementación para crear IFLightDAO. Si el Servicio no está creando explícitamente sus dependencias inyectadas por el contenedor, los detalles de configuración y la creación de objetos se representarán en el contenedor. Esto permite que los componentes en una aplicación se conecten fácilmente juntos, con diferentes configuraciones y elimina una gran cantidad de código de fábrica y singleton y fábrica.
Una implementación de la clase, que se basa en una implementación de IFLightdao declarada con JSR 250 Anotación de recursos, puede verse así:
Clase pública TravelAgencyServiceImpl implementa ITTRAVELAGENCYService
{
@Resource (name = "Flightdao")
Public Iflightdao Flightdao;
Public void booktrip (Long OutboundFlightid, Long Returnflightid, int Seats)
lanza inválida de la concepción
{
Reserveseats (Outboundflightid, asientos);
Reserveseats (returnflightid, asientos);
}
}
En este caso, el contenedor proporcionará la implementación correcta de un recurso llamado "Flightdao" a la clase de servicio. Pero, ¿qué pasa si desea aprovechar la inyección de recursos ahora en lugar de esperar la liberación de EJB 3.0? Ok, puede tomar un contenedor liviano: puede proporcionar inyecciones de dependencia como resorte o contenedor Pico. Sin embargo, no entiendo que haya un contenedor liviano: puede usar JSR 250 anotaciones de recursos para especificar los requisitos de inyección (aunque estoy ansioso por algunos a este respecto).
Una solución es usar aspectos para implementar la inyección de dependencia. Si usa la anotación @Resource para esto, su implementación será consistente con el EJB 3.0 Way y hacia adelante compatible con la implementación EJB 3.0, y eso no es algo muy difícil de implementar. La siguiente lista muestra un aspecto creado con SuppeJ: inyecta campos anotados con la anotación @Resource:
@aspecto
Inyección de clase pública
{
Private DependencyManager Manager = new DependencyManager ();
@before ("Get (@Resource * *. *)")
Vacío público antes de los camposes (unión de unión de estejoinpoint)
arroja ilegalargumentException, ilegalaraccessexception
{
FieldSignature Signature = (FieldSignature) thisJoinPoint.getSignature ();
Resource injectAnnotation = Signature.getField (). GetAnnotation (Resource.Class);
Object Dependency = Manager.Resolve Dependency (Signature.getFieldType (), inyectAnnotation.name ());
firma.getfield (). set (thisjoinPoint.getThis (), dependencia);
}
}
Todo este aspecto simple que hace es consultar la clase de implementación de un archivo de propiedad (esta lógica está encapsulada en el objeto DependencyManager) y inyectarla en los campos anotados con la anotación @Resource antes de acceder al campo. Obviamente, esta implementación no está completa, pero ilustra cómo puede proporcionar inyección de recursos de una manera compatible con JSR 250 sin EJB.
4. Seguridad
Además de la inyección de recursos, JSR 250 y EJB 3.0 también proporcionan una representación segura de metadatos a través de la anotación. El paquete Javax.Annotation.Security define cinco anotaciones (Runas, RolesLawed, Permitall, DeneLall y Roleserferenced, todo lo cual puede aplicarse a los métodos para definir los requisitos de seguridad. Por ejemplo, si desea declarar que el método BookFlight enumerado anteriormente solo puede ser ejecutado por las personas que llaman con el rol de "usuario", puede anotar este método con las siguientes restricciones de seguridad:
Clase pública TravelAgencyServiceImpl implementa ITTRAVELAGENCYService
{
@Resource (name = "Flightdao")
Public Iflightdao Flightdao;
@RolesAllowed ("usuario")
Public void booktrip (Long OutboundFlightid, Long Returnflightid, int Seats)
lanza inválida de la concepción
{
Reserveseats (Outboundflightid, asientos);
Reserveseats (returnflightid, asientos);
}
}
Esta anotación indicará que el contenedor es responsable de garantizar que solo la persona que llame del rol especificado pueda ejecutar este método. Así que ahora mostraré otro aspecto simple: fortalecerá aún más las limitaciones de seguridad en la aplicación:
@aspecto
Seguridad de clase pública
{
@around ("Ejecución (@javax.annotation.security.roleslewed * *. *(..))")
OBJETO PÚBLICO alrededor de los medios de comunicación (procediendo un punto de vista de este solo punto)
Lanza lanzamiento
{
Boolean Callerauthorized = false;
RolesLlowed RolesLlowed = RolesLlowedForJOINPOINT (este punto de rótula);
para (rol de cadena: roles eLlowed.Value ())
{
if (CallerInrole (rol))
{Callerauthorized = True;
}
if (Callerauthorizado)
{return thisjoinpoint.proced ();
demás
{
tirar nueva RuntimeException ("Llama no autorizada para realizar la función especificada");
}
}
PRIVADO Roles realizó RolesLlowedForjoinPoint (ProcedingJOINPOINTO ESTE JOINPOINT)
{
MethodSignature MethodeSignature = (Methodsignature) thisjoinPoint.getSignature ();
método TargetMethod = Methodsignature.getMethod ();
return TargetMethod.getAnnotation (RolesLlowed.Class);
}
Private Boolean CallerInrole (rol de cadena)
{...}
}
Este aspecto incluye la ejecución de todos los métodos: verificar que la persona que llama es uno de los roles especificados en la anotación, anotar con la anotación @RolesAllowed y garantizar que la persona que llame esté autorizada para llamar al método. Por supuesto, también puede usar cualquier algoritmo que desee autorizar al usuario y recuperar su papel, como JAAS o una solución personalizada. En este programa de ejemplo, por conveniencia, elegí representar al contenedor de servlet.
V. Asuntos
Las transacciones se convierten en una parte importante del desarrollo empresarial, porque facilitan la integración de datos en un entorno concurrente. Desde un alto nivel, las transacciones pueden garantizar esto a través de operaciones múltiples o completas o incompletas.
A diferencia de las anotaciones para la inyección y la seguridad de los recursos, las anotaciones para las transacciones son específicas de EJB 3.0 y no se definen en las anotaciones normales JSR 250. EJB 3.0 define dos anotaciones asociadas con las transacciones: gestión de transacciones y transaccionesattribute. La anotación de TransactionManager especifica si la transacción es administrada por el contenedor o por el bean. En EJB 3, si esta anotación no se especifica, se utilizará la transacción administrada por el contenedor. La anotación de TransactionAttribute se utiliza para especificar el nivel de propagación de la transacción del método. Los valores válidos, incluidos los obligatorios, requeridos, requeridos, nuevos, compatibles, sin apoyo y nunca admitidos, se utilizan para definir si se requiere una transacción existente o se inicia una nueva transacción, etc.
Debido a que la operación de BookFlight consta de dos pasos: ordenar un vuelo saliente y un vuelo de regreso, al empaquetarlo en una transacción, puede garantizar la consistencia de la operación. Al usar anotaciones de transacción EJB 3.0, esto se verá así:
Clase pública TravelAgencyServiceImpl implementa ITTRAVELAGENCYService
{
@Resource (name = "Flightdao")
Public Iflightdao Flightdao;
@RolesAllowed ("usuario")
@TransactionAttribute (TransactionAtTributEType.Required)
Public void booktrip (Long OutboundFlightid, Long Returnflightid, int Seats)
lanza inválida de la concepción
{
Reserveseats (Outboundflightid, asientos);
Reserveseats (returnflightid, asientos);
}
}
Y puede aplicar un aspecto simple para definir automáticamente los límites de transacciones:
@aspecto
Transactionidad de clase pública
{
@PointCut ("Ejecution (@javax.ejb.transactionAttribute * *. *(..))")
public void transaccionAlMethods () {}
@before ("TransactionAlMethods ()")
Public Void BeforetransactionalMethods ()
{HibernateUtil.BeginTransaction ();
@AfterReturning ("TransactionAlMethods ()")
Vacío público después de la returación
{HibernateUtil.CommitTransaction ();
@Afterthrowing ("TransactionAlMethods ()")
Vacío público después de lanzartransactionalMethods ()
{HibernateUtil.RollbackTransaction ();
}
Esta implementación se basa en la suposición de que se utiliza un patrón local de hilos hibernados y ubicuos para administrar sesiones de hibernación y objetos de transacción;
6. Resumen
Al utilizar los conjuntos de anotaciones EJB 3.0 y JSR 250, este artículo ha mostrado cómo las preocupaciones transversales como la gestión de recursos, la seguridad y las transacciones se implementan como aspectos. Por supuesto, hay muchos otros contenidos que necesitamos aprender más. Lo primero que debe aprender es el plan proporcionado por las preocupaciones transversales modulares al implementar estos aspectos de ejemplo usando SuppeJ. En segundo lugar, hemos visto algunas nuevas ideas y conceptos detrás de la declaración EJB 3.0 que ahora está surgiendo. Finalmente, también vemos de manera dramática la libertad que debe proporcionarse para desacoplar nuestros objetos comerciales de la API EJB. En este punto, todo lo que desea hacer TravelAgencyServiceImpl es una sesión sin estado es agregar una última nota:
@stateful
Clase pública TravelAgencyServiceImpl implementa ITTRAVELAGENCYService
{...}
Finalmente, realmente espero que este enfoque gratuito para proporcionar servicios empresariales brinde competencia e innovación en la industria del marco/contenedores.