19 Nov

Extensión de Spring Boot para el framework Stripes

Stripes y Spring Boot

Hemos tenido oportunidad recientemente de incorporar Spring Boot dentro de nuestro stack tecnológico y hemos podido comprobar de primera mano por qué ha ganado este año el premio a la contribución más innovadora al ecosistema Java en los JAX Innovation Awards.

Por otra parte, mucho menos conocido pero no por ello exento de calidad es el framework Stripes, un framework web, que sigue el patrón MVC, se apoya fuertemente en la configuración por convención y que sobretodo es tremendamente sencillo. No tiene esa infinidad de posibilidades que aporta, por ejemplo, Spring MVC, pero para el 99.9% de las funcionalidades que va a tener un portal web típico, (para nosotros) es más que suficiente. Otro de los puntos fuertes de este framework es lo «natural» que resulta, cómo todo funciona como se espera, sin sorpresas desagradables, y lo fácil que es extenderlo.

Precisamente por ser un framework cuyo uso comparado con su competencia es muy residual, no existe un módulo que de integración con Spring Boot, lo que nos ha supuesto una excusa inmejorable para desarrollarlo y, de paso, aprender su funcionamiento interno. El código resultante está disponible en github.

Desarrollo de una extensión Spring Boot

La guía de referencia de Spring Boot es un excelente recurso de partida para acometer nuevas extensiones de este framework, que será de dostres módulos maven:

  • starter: en realidad, un jar (casi)vacío, que fundamentalmente sirve para proveer las dependencias por defecto que se traerá el módulo spring-boot. Al margen de esto, contiene un fichero ./META-INF/spring.provides dónde se referencia al siguiente módulo,
  • autoconfigure: que contiene la magia de Spring Boot; se encarga de instanciar y configurar lo que sea necesario y, opcionalmente, ofrecer un namespace a partir del cual obtener valores de configuración. Las dependencias de este módulo deben ser marcadas como opcionales, de tal modo que no sean arrastradas por éste.
  • sample: no es realmente necesario, pero tener un ejemplo que integre el módulo desarrollado favorece el uso de la extensión. En nuestro caso convertiremos la calculadora del tutorial de inicio con Stripes a una aplicación Spring Boot.

Contenido del módulo autoconfigure

El punto de entrada se encuentra en el fichero ./META-INF/spring.factories que referencia a una clase de configuración de Spring a partir de la entrada org.springframework.boot.autoconfigure.EnableAutoConfiguration:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=net.sourceforge.stripes.springboot.autoconfigure.StripesAutoConfiguration

La clase StripesAutoConfiguration es una clase de configuración de Spring (por tanto, anotada con @Configuration), que se encarga de instanciar dos FilterRegistrationBeans que contienen tanto el StripesFilter como el DynamicMappingFilter de Stripes. Para este caso en concreto, se definen además otros beans de Spring que sobrescriben y desactivan el uso de Spring MVC.

@Configuration
@ConditionalOnClass( name="net.sourceforge.stripes.springboot.autoconfigure.SpringBootVFS" ) // @see http://stackoverflow.com/a/25790672
@ConditionalOnProperty( name = "stripes.enabled", matchIfMissing = true )
@EnableConfigurationProperties( StripesProperties.class )
public class StripesAutoConfiguration {

private static final Log LOG = Log.getInstance( StripesAutoConfiguration.class );
[...]

    @Bean( name = "stripesDynamicFilter" )
    @ConditionalOnMissingBean( name = "stripesDynamicFilter" )
    public FilterRegistrationBean stripesDynamicFilter() {
        final DynamicMappingFilter filter = new DynamicMappingFilter();

        final List< String > urlPatterns = new ArrayList< String >();
        urlPatterns.add( "/*" );

        final FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter( filter );
        registration.setUrlPatterns( urlPatterns );
        registration.setDispatcherTypes( DispatcherType.REQUEST, DispatcherType.INCLUDE, DispatcherType.FORWARD, DispatcherType.ERROR );
        registration.setOrder( Ordered.LOWEST_PRECEDENCE );
        return registration;
}

[...]

Se observa además que esta clase se encuentra anotada a nivel de clase y métodos con distintas anotaciones de tipo @ConditionalOnXXX, que son las que consiguen que la configuración sea opcional en función del entorno, la existencia o no de otros beans… Son el centro de la «magia» de Spring Boot. Es un mecanismo extremadamente sencillo y potente que, junto con una elección inteligente de unos valores por defecto (y que pueden ser fácilmente sustituidos), son la base del éxito de este framework. Chapeau por las mentes pensantes detrás de este invento.

Sumado a todo esto, esta clase se encuentra anotada con @EnableConfigurationProperties( StripesProperties.class ), que indica la clase a través de la cuál se reserva, en este caso, el namespace stripes en el fichero application.properties. Esta clase es un POJO normal y corriente, cuyas variables de clase se corresponderán con las equivalentes del fichero application.properties y cuya única particularidad es que se encuentra anotada con @ConfigurationProperties, dónde se indica el namespace a reservar:

@ConfigurationProperties(prefix = StripesProperties.STRIPES_PREFIX )
public class StripesProperties {

    public static final String STRIPES_PREFIX = "stripes";

    /** value for: {@code ActionBeanPropertyBinder.Class} */
    private String actionBeanPropertyBinder;

    /** value for: {@code ActionBeanContextFactory.Class} */
    private String actionBeanContextFactory;

    /** value for: {@code ActionBeanContext.Class} */
    private String actionBeanContext;

[...]
    /** placeholder for custom configuration */
    private Map< String, String > customConf = new HashMap< String, String >();

[...]

// getter & setters

[...]
}

Como curiosidad, en esta clase se incluye un Map a través del cuál se recogen todo tipo de valores que serán añadidos a la configuración del filtro de Stripes de tal modo que una entrada del tipo stripes.custom-conf.MY_CUSTOM_KEY=MY_CUSTOM_VALUE en el fichero application.properties de Spring Boot será añadido al filtro de Stripes como un parámetro de configuración con clave MY_CUSTOM_KEY y valor MY_CUSTOM_VALUE.

Contenido del módulo sample

Aunque no es estrictamente necesario, y la guía de referencia de Spring Boot no lo menciona, es muy de agradecer disponer de un ejemplo funcionando de la extensión desarrollada, y la mejor manera de promover el uso del mismo. En este caso, la aplicación se corresponde con la calculadora del tutorial de inicio al framework Stripes. El módulo es un módulo maven normal, cuyo pom.xml incluye la ejecución del plugin org.springframework.boot:spring-boot-maven-plugin y que contiene la clase java y jsp del tutorial tal cuál están en el ejemplo. Por último se añade un fichero application.properties y se indican las configuraciones de Stripes necesarias para arrancar la aplicación (nota: la extensión es lo suficientemente inteligente como para configurar el framework con unos valores por defecto lo suficientemente razonables como para poder arrancar una aplicación sin necesidad de proveer ningún valor específico).

Una vez compilados todos los módulos, puede arrancarse la aplicación desde el mismo módulo sample bien ejecutando un mvn spring-boot:run, o bien un java -jar target/stripes-spring-boot-sample-1.0.0.jar, y la aplicación quedará accesible en http://localhost:8080/index.jsp.

Una vez realizado todo el desarrollo, se anunció en la lista de distribución de Stripes, con la intención de que fuese integrado dentro de la distribución principal por lo que, con un poco de suerte estará disponible en la versión 1.7.0 del framework.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *