Quitando accesos a la Request

Una de las ideas principales cuando se implementa una solución java mediante algunos frameworks es independizarnos del servlet. Esto es, evitar en gran medida utilizar el contexto del servlet como almacen de cosas que queremos intercambiar entre clases. Idealmente, en caso de producirse, este acceso debería ser lo más transparente posible al programador.
En cualquiera de los casos algunas veces no nos queda más remedio y cuando se utiliza struts2 este nos proporciona interfaces que nos permiten un acceso cómodo a la request o a la session.
Para acceder a la request implementamos el interfaz "ServletRequestAware" y cuando actúe el interceptor apropiado, éste nos poblará el request definido en el action. Con este HttpServletRequest ya podemos tirar de él y hacer el getAttribute de la session, capturar la ip desde la que realizan la petición o sacar algo de la HttpSession con el  request.getSession.getAttribute("loquesa") etc.
Para acceder a la "casi-session" se utiliza el SessionAware, y digo casi-session, pues no nos puebla un HttpSession, nos puebla algo más genérico, un Map<String, Object>. Esto es, en vez de hacer un session.getAttribute("loquesea") haremos un session.get("loquesea"), como hacemos con un map de este tipo.
Todo esto de meter, sacar, e intercambiar objetos a través de la sessión lo hacemos a diarío y funciona. Peeeeeero, se puede hacer más elegante.
El caso a estudio es una aplicación con Struts2 y Spring para inyección de dependencias. En un caso típico los action de struts tendrán un scope "singleton" o "prototype" por razones de eficiencia, y habrá uno o varios objetos que deberan persistir entre los distintos action.
La solución inmediata es crear unos bean contenedores e inyectarlos en los action, a esos bean contenedores les damos un scope de session y se mantendrán durante la sessión. La idea en sí es muy buena, pero si la intentamos implementar de forma directa peta. ¿Por qué? Pues peta porque Spring no sabe, a priori, cómo gestionar algo que tiene una duración temporal con algo que tiene otro tipo de duración, esto es, "scopes" incompatibles.
Para que la solución anterior funcione necesitamos de la otra "magia" que nos proporciona Spring, aparte de la inyección de dependencia. Esta herramienta mágica se llama AoP o programación orientada a aspectos.
A efectos prácticos lo que tenemos que decirle al framework es que lo inyecte no de una forma rígida, como hace la inyección "normal", sólo cuando y durante el tiempo que sea preciso, para que no choquen los "scope" de los bean.
Veamos como quedaría el bean receptor:

    <bean id="loginAction" class="es.home.action.LoginAction" scope="prototype">
        <property name="user" ref="user" />
    </bean>


Para este ha de ser transparente la inyección. El Bean user sería algo así:

    <bean id="user" class="es.home.data.User" scope="session">
        <aop:scoped-proxy />
    </bean>


la gracia, está en indicarle con  "<aop:scoped-proxy /> " que haga la inyección mediante AoP. Sin lo cual rajaría al instanciar el bean "loginAction".

Nota: El proyecto "base" creado en otras entradas sobre struts2+Spring no tiene soporte completo para Spring, si se desea que funcione se deberan añadir al pom librerias de Spring Yo he añadido estas:
     
     <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>3.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib-nodep</artifactId>
            <version>2.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>3.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-asm</artifactId>
            <version>3.1.0.RELEASE</version>
        </dependency>
 

Comentarios