Integrar Struts con Spring – Teoría
Bueno, ya tenemos un proyecto con Spring – MVC (holamundo) y otro con Struts (holamundoStruts138). Cuál utilizaremos para desarrollar ? Eso lo dejo para otra discusión.
Aquí quiero señalar que existe otra solución, y es integrar Struts con Spring, es decir, utilizar Struts aprovechando sus puntos fuertes como MVC (madurez, documentación, podemos extender el framework con Struts-Validator y Tiles…) y Spring aprovechando también sus puntos fuertes (como AOP, IoC, DI…).
El framework de Struts realiza una serie de operaciones transparentes para el desarrollador para facilitarle la vida. Entre ellas mantiene un HashMap que contiene referencias a objetos Action ya instanciados. Ante cada petición mira primero este HashMap para ver si contiene la clase Action solicitada. Si es así recupera el objeto a partir de la referencia almacenada en el HashMap; y si no instancia e inicializa la clase Action y guarda su referencia en el HashMap.
Al manejar una única instancia de cada Action se ahorra bastante tiempo y el rendimiento de la aplicación mejora notablemente, pero este mecanismo podría ser más eficiente, ya que cada Action invoca a uno o varios objetos de negocio que con Struts se deben instanciar e inicializar en cada llamada.
La integración con Spring perfecciona este mecanismo aprovechando IoC y DI. Las clases Action de Struts pasan a ser beans gestionados en el contexto de Spring, y permitiendo que Spring aplique IoC y DI también a los Action de Struts conseguimos que las instancias de estas clases Action ya tengan inyectadas (instanciados e inicializados) los objetos de negocio, mejorando considerablemente el rendimiento de nuestra aplicación: al levantar la aplicación será un poco lenta pero después irá como un tiro.
Pues manos a la obra. Debemos declarar un bean en el contexto de Spring que represente nuestro Action para que sea Spring quien le instancie y le inyecte sus dependencias (los objetos de negocio).
Donde gestiona Struts la creación de sus clases Action ? En el método
processActionCreate de su controlador,
RequestProcessor.
Vale, pues sobre escribamos esta clase con nuestro propio controlador,
AppRequestProcessor, para que pida la instancia del bean al contexto de Spring (la rama true del if). Si existe la instancia será la que manejemos; sino existe la crearemos como se hacía con Struts (la rama del else). Lo que está en negrita es la clave, sólo un if.
Si queremos utilizar Tiles debemos extender de
TilesRequestProcessor.
public class AppRequestProcessor extends RequestProcessor {
. . .
protected Action processActionCreate(HttpServletRequest request,
HttpServletResponse response, ActionMapping mapping)
throws IOException {
// Acquire the Action instance we will be using (if there is one)
String className = mapping.getType();
if (log.isDebugEnabled()) {
log.debug(” Looking for Action instance for class “ + className);
}
// If there were a mapping property indicating whether
// an Action were a singleton or not ([true]),
// could we just instantiate and return a new instance here?
Action instance;
//Acceso sincronizado al HasMaps de actions
synchronized (actions) {
// Return any existing Action instance of this class
instance = (Action) actions.get(className);
if (instance != null) {
if (log.isTraceEnabled()) {
log.trace(“ Returning existing Action instance”);
}
return (instance);
}
// Create and return a new Action instance
if (log.isTraceEnabled()) {
log.trace(“ Creating new Action instance”);
}
try {
//String beanName = determineActionBeanName(mapping);
String beanName = mapping.getType();
if (getWebApplicationContext().containsBean(beanName))
instance = (Action)getWebApplicationContext().getBean(beanName, Action.class);
else
instance = (Action) RequestUtils.applicationInstance(className);
// Maybe we should propagate this exception
// instead of returning null.
} catch (Exception e) {
log.error(getInternal().getMessage(“actionCreate”,
mapping.getPath()), e);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
getInternal().getMessage(“actionCreate”, mapping.getPath()));
return (null);
}
actions.put(className, instance);
}
if (instance.getServlet() == null) {
instance.setServlet(this.servlet);
}
return (instance);
}
. . .
}
Es decir, buscamos si el nombre del bean (beanName) existe en el contexto de Spring, y si es así lo obtenemos de ahí. Para que funcione debemos utilizar como nombre del bean que representa la clase Action en el contexto de Spring un nombre que Struts pueda obtener, por ejemplo:
- El nombre lo podemos obtener de la ruta (path) mediante determineActionBeanName(mapping), el método que está comentado en este ejemplo.
- O bien lo podemos obtener como se muestra en el ejemplo del “type” del mapping, es decir el nombre de la clase Action.
En el contexto de Spring debemos declarar nuestros actions, utilizando como nomenclatura para sus nombres una de las dos opciones anteriormente propuestas. En el primer caso el nombre del bean será la ruta introducida en el navegador : “/editarDatos” y “/guardarDatos”. Ojo, porque en este caso que todos los beans del mismo action deben declarar los mismos BO’s porque la instancia que se almacenará será la que se instancia primero, es decir por la primera ruta a la que se acceda, por lo cual hay que tener ojo al utilizar wildcards.
<bean name=“parentAction” class=“es.xxx.xxx.control.action.base.AppBaseAction” abstract=“true” />
<bean name=“/editarDatos” class=“es.xxx.xxx.control.action.DatosAction” singleton=“false” parent=“parentAction”>
<property name=“datosBO”><ref bean=“datosBO” /></property>
</bean>
<bean name=“/guardarDatos” class=“es.xxx.xxx.control.action.DatosAction” singleton=“false” parent=“parentAction”>
<property name=“datosBO”><ref bean=“datosBO” /></property>
</bean>
<bean name=“/validarDatos” class=“es.xxx.xxx.control.action.DatosAction” singleton=“false” parent=“parentAction”>
<property name=“datosBO”><ref bean=“datosBO” /></property>
</bean>
En el segundo caso el nombre del bean debe ser el “tipo” del action, es decir “es.xxx.xxx.control.action.DatosAction”.
<bean name=“parentAction” class=“es.xxx.xxx.control.action.base.AppBaseAction” abstract=“true” />
<bean name=“es.xxx.xxx.control.action.DatosAction” class=“es.xxx.xxx.control.action.DatosAction” singleton=“false” parent=“parentAction”>
<property name=“datosBO”><ref bean=“datosBO” /></property>
</bean>
En ambos casos se apoyarían sobre un bean de negocio
<bean name=“baseBO” class=“es.xxx.xxx.negocio.base.BaseBOImpl” abstract=“true”/>
<bean id=“datosBO” class=“es.xxx.xxx.negocio.impl.DatosBOImpl” parent=“baseBO”>
<property name=“datosDAO” ref=“datosDAO” />
</bean>
que se apoya sobre otro de persistencia
<!– SqlMap setup for iBATIS Database Layer –>
<bean id=“sqlMapClient” class=“org.springframework.orm.ibatis.SqlMapClientFactoryBean”>
<property name=“configLocation”>
<value>classpath:/es/xxx/xxx/persistencia/impl/xml/sql-map-config.xml</value>
</property>
<property name=“dataSource” ref=“dataSource”/>
</bean>
<!– Generic Dao – can be used when doing standard CRUD –>
<bean id=“dao” class=“es.xxx.xxx.persistencia.base.BaseDaoImpl” abstract=“true”>
<property name=“sqlMapClient” ref=“sqlMapClient”/>
</bean>
<bean id=“datosDAO” class=“es.xxx.xxx.persistencia.impl.DatosProyectoDAOImpl” parent=“dao”/>
Qué fácil, una vez que se sabe !
También te puede interesar:
- Web Services – Integrar los clientes en Spring Ya sabemos cómo publicar un servicio web y cómo construir un cliente que consuma dicho servicio partiendo del fichero descriptor del contrato. Ahora integraremos el...
- [Struts] – ActionDispatcher Struts permite manejar eventos HTML, mediante la clase ActionDispatcher, LookupDispachAciton y MappingDispatchAction que encontramos en el paquete org.apache.struts.actions. En la clase Action declaramos un ActionDipatcher...
- Spring, Struts 1.3.8, JDBC y MySQL Vaya combinación, ya se va complicando el tema. Ahora que ya tenemos un servidor de base de datos MySQL disponible, queremos utilizarlo en nuestros proyectos...
- [Struts] – no Cache Si queremos que ninguna página de nuestra aplicación basada en Struts almacene los datos introducidos por el usuario en ellas (lo que se entiende por...
- Framework Struts Un esquema de su funcionamiento podría ser el siguiente: JSP Manda datos introducidos por el usuario al Action Pinta los datos recibidos del Action FORM...































Lycka Bonita » Integrar Struts con Spring - holamundoStruts138Spring dijo
21 de July del 2008 a las 10:45 am
[...] Vamos al turrón, vamos a implementar lo que hemos visto a nivel teórico. [...]
walter dijo
25 de August del 2008 a las 9:09 pm
no entendi nada :s
walter dijo
25 de August del 2008 a las 9:10 pm
yo la teoria mas o menos la conosco pero me al momento de usar los bean .. siempre me tira error :S
Javier dijo
26 de June del 2009 a las 6:34 am
Considero que se debe ser más detallista con el código, la parte teorica suena muy bonita, pero en el momento de implementar me doy de topes, envio saludos y gracias…
yoyoooyoy dijo
26 de June del 2009 a las 7:13 am
Bueno, todo el código que se necesita está ya escrito en la entrada, así que lo que falla va a ser que no está bien explicado.
Lo intentaré corregir pronto.
yoyoooyoy dijo
10 de March del 2011 a las 9:44 am
Año y medio después, he vuelto a redactar esta entrada, espero que haya quedado más clara la idea ahora.