domingo, 18 de mayo de 2008

Integrar Spring con Struts

¿Cómo podemos usar Spring como framework para la capa de negocio y struts para la presentación?

El problema radica en que Spring es un framework empresarial "ligero". De esta forma, su tecnología IoC (inyección de dependencias) solo tiene alcance en el propio framework Spring y no inyecta dependencias en Struts. Si no inyecta dependencias en Struts, ¿como podemos desde struts llamar a los métodos de negocio implementados por Spring? En este tutorial intentaremos dar respuesta a esta pregunta. Tenemos el fichero de configuración de Struts que tendrá la información pertinente a los ActionForm y los Action, principalmente, junto con otra información adicional como los global-exceptions, etc., el fichero de configuración de struts (struts-config.xml) ¡no es necesario tocarlo con este método que vamos a mostrar para integrar struts con spring!.

El único fichero que tocaremos será web.xml.

Pero antes de nada, vamos por partes:

1) Lo primero es tener el fichero de configuración de Spring que tendrá una pinta como esta (versión 2.5)




xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">





Podemos comprobar como se han activado con la línea el manejo de las anotaciones de las clases para que quede al más puro estilo EJB3. De este modo, las clases de negocio de Spring basta con anotarlas con @Service, por ejemplo:

/* Interfaz de negocio (el equivalente al @Local de EJB, nótese que no requiere anotación en Spring) */
package com.myapp.negocio;

public interface IUnServicio {

boolean login(String user, String pass);

}

/* Implementación de la interfaz, note que para indicarle a Spring que es un objeto de negocio se usa la anotación @Service (sería el "equivalente" a @Stateless de EJB3) */
package com.myapp.negocio;

import org.springframework.stereotype.Service;

@Service
public class UnGranServicioBean implements IUnServicio {
public boolean login(String user, String pass) {
return user.equals("jjj") && pass.equals("mmm");
}
}

Siguiendo con el fichero de configuración de Spring, la línea le indica a Spring que rastree todas las clases del paquete indicado en el atributo "package" en busca de aquellas que estén anotadas (en nuestro caso con @Service, aunque serviría @Component y @Repository) y mantenerlas (posibilidad de inyección de dependencias en otras clases, etc.,).

La última línea del fichero de configuración indica que se active la programación orientada a Aspectos (implementada por AspectJ que es el framework dónde se apoya Spring). De este modo si se encuentran Aspectos se compilan y tejen como si usáramos AspectJ.

Hay que tener en cuenta que para activar AspectJ necesitamos tener dicha librería en el PATH. En el framework de Spring si nos lo bajamos con las dependencias tenemos en la carpeta LIB el jar correspondiente a AspectJ por lo que en teoría no deberíamos de bajarnos nada más. Para integrar AspectJ con Spring basta con añadir al PATH una librería más, la librería correspondiente a AspectJ que se encuentra en la subcarpeta Module del framework de Spring.

Con el fichero de configuración de Spring, Struts y los @Service listos junto con las librerías de Spring necesarias, basta añadir las siguientes líneas al fichero web.xml para integrar Spring con Struts:



org.springframework.web.context.ContextLoaderListener


¿Cómo accedo, por tanto, al ApplicationContext de Spring para obtener los objetos de negocio?

Basta con cambiar la clase que hereda los Action por ActionSupport. Por ejemplo:

package com.myapp.struts;

import com.myapp.negocio.IUnServicio;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForward;
import org.springframework.web.struts.ActionSupport;

// Nota como la clase que hereda es ActionSupport en vez del clásico Action de Struts.
public class LoginAction extends ActionSupport {

private final static String SUCCESS = "success";

public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
IUnServicio servicio = (IUnServicio) this.getWebApplicationContext().getBean("unServicio");
return mapping.findForward(SUCCESS);

}
}

Esta ActionSuppor nos permite sacar el contexto de Spring con getWebApplicationContext() y ahora si podemos sacar los objetos de negocio.

El nombre del objeto de negocio es el nombre de la interfaz en minúscula la primera letra. Por ejemplo, si nuestra interfaz se llama MiInterfaz, tendremos que preguntar por getWebApplicationContet().getBean("miInterfaz"). También hay que tener en cuenta que si seguimos la convención de que los nombres de las interfaces empiecen por 'I' latina mayúscula, Spring la omite para el nombre. De este modo, la interfaz IMiInterfaz la conseguiremos del mismo modo que MiInterfaz, preguntando por "miInterfaz".

Existen más métodos para integrar Struts con Spring. Este método es el más sencillo pero provoca que se acoplen Spring y Struts. Esto no debería ser un problema si la apuesta es segura. Los otros métodos requieren cambiar muchos parámetros de los ficheros de configuración de ambas herramientas lo que provoca, finalmente, que se acoplen a nivel de ficheros de configuración, por lo que personalmente prefiero este método que para desacoplar si, por ejemplo, se decide usar EJB en vez de Spring, bastaría con renombrar los ActionSupport por Action (un simple Replace All en cualquier IDE) y eliminar la línea de de web.xml.

3 comentarios:

sickdhartha dijo...

no me gusto tu tutorial no hay ejemplos claros ni especificaciones de algunos elementos estrucutralo mejor y suerte para la proxima no me sirvio de nada tu tutorial.

Jorge Cantón Ferrero dijo...

Pues lo siento mucho sickdhartha, espero que otros tutos si te ayuden.

Daniel dijo...

Esta buena la explicación, clara y simplificada... te felicito por e apoyo que das para los que quieren aprender.

Saludos.