Jul 17

Puñetitas con SpringBoot y RestTemplateBuilder

Cuando en Spring Boot queremos hacer un cliente REST, podemos usar RestTemplate. Esta clase permite hacer llamadas REST al servidor.
Para evitar en todas las llamadas poner la URL completa, se puede poner la URL base de esta forma

RestTemplateBuilder builder = new RestTemplateBuilder();
RestTemplate restTemplate = builder.rootUri(“http://loquesea.com/”).build();

// y a partir de aqui, para una llamada GET por ejemplo
restTemplate.getForObject(“/entidad”, ….);

En getForObject() no hace falta poner la URL completa, basta empezarla con / y el rootUri que añadiemos anteriormente se añade al principio.

Pues bien, esto funciona bien, pero cuando hice mi primera prueba, iluso de mí, se me ocurrió poner esto

RestTemplateBuilder builder = new RestTemplateBuilder();
builder.rootUri(“http://loquesea.com/”)
RestTemplate restTemplate = builder.build();

peeero … ¡¡eso no funciona!!. ¿Por qué?. Metiéndome en el código del método rootUri() me asombra ver

/**
* Set a root URL that should be applied to each request that starts with {@code ‘/’}.
* See {@link RootUriTemplateHandler} for details.
* @param rootUri the root URI or {@code null}
* @return a new builder instance
*/
public RestTemplateBuilder rootUri(String rootUri) {
return new RestTemplateBuilder(this.detectRequestFactory, rootUri,
this.messageConverters, this.requestFactorySupplier,
this.uriTemplateHandler, this.errorHandler, this.basicAuthorization,
this.restTemplateCustomizers, this.requestFactoryCustomizers,
this.interceptors);
}
}

Lo advierte el comentario, devuelve una nueva instancia, por lo que la rootUri no se guarda en la instancia actual. Así que esta llamada solo funciona si se pone todo seguido como en el primer ejemplo rootUri(..).build(), o si nos guardamos en una nueva variable lo que devuelve rootUri() para luego llamar a buld() de lo devuelto.

En fin, despista un poco.

Jun 10

Estructura de Plugins con OSGI / Spring Boot

osgi

spring boot

Estoy empezando una aplicación java, de escritorio, desde cero. Una de las cosas que pretendo hacer es que tenga plugins que se puedan instalar de forma adicional, no solo en el lado de la consola (javax.swing), sino también funcionalidades en el lado del servidor (java de escritorio).

Me he planteado dos opciones. Una es usar OSGI, que es el framework más estándar y conocido para hacer una aplicación modular con plugins. Pero aunque no está pensado para ello, se me ha ocurrido otra forma de hacerlo usando Spring Boot (por ir a lo más moderno).

Con OSGI, cada jar lleva un fichero de manifiesto donde indica qué paquetes java exporta a otros jar y qué paquetes java necesita de otros jar. Si el fichero de manifiesto no exporta o importa paquetes, el desarrollador no puede usar los paquetes que no han sido exportados/importados, el mismo IDE debidamente montado no le deja.

Con Spring Boot no hay esta opción de importar y exportar paquetes, pero se puede “apañar” con disciplina. Debemos montar una estructura de proyectos/subproyectos donde haya jar que sólo tengan interfaces o estructuras de datos. Los demás jar donde está el código sólo pueden depender de estos jar de interfaces/estructuras de datos. Esto se puede montar correctamente con maven/gradle. Puede quedar quizás una estructura de proyecto/subproyectos un poco engorrosa, pero si organizada y que impide al desarrollador usar en un proyecto cosas que no debe de otro (siempre que no se líe a tocar dependencias maven/gradle)

Para enganchar las distintas clases/servicios entre si de distintos jar, OSGI ofrece lo que llama Declarative Services. Cada jar registra en OSGI los servicios que ofrece (clases que implementan una interfaz java y que ofrecen alguna funcionalidad) y cada jar pide a OSGI los servicios que necesita (servicios a través de interfaces java y que necesita que alguien se las dé ya implementadas) . OSGI se encarga de “enganchar” en el arranque, automáticamente, a unos con otros en función de lo que ofrecen y necesitan.

Con Spring Boot, está el mecanismo que tiene de inyección de dependencias y anotaciones. Si una clase necesita un servicio, le basta con poner un atributo con la interfaz de ese servicio anotada con @Autowired. Si Un jar ofrece un servicio, basta que le ponga a la clase que lo ofrece la anotación @Service (o cualquiera de las alternativas, como @Component u otras). Spring Boot se encarga de ver qué servicios se ofrecen e inyectarlos en las clases que lo necesitan.

De una forma o de otra, el mecanismo de plugin sería que la aplicación principial definiera la interfaz que deben implementar los plugins y los servicios que deben ofrecer para integrarse correctamente en la aplicación. Por ejemplo, en la interfaz de usuario la interfaz que deben implementar los plugins pueden tener métodos como getActions() para añadir dichas acciones a un menú o barra de herramientas, getIcon() para poner el icono de dicho plugin en algún sitio, getPanel() para que el plugin pueda proporcionar su propio panel visual, etc. La aplicación principal pediría al framework todas las clases que ofrezcan este servicio (implementen esta interfaz) y los plugin presentes registrarían sus servicios en el framework.

¿Qué ventajas/inconvenientes tiene cada mecanismo?

OSGI es el estándar para plugins, y además permite el añadir plugins en caliente. Debidamente configurado, bastaría situar el jar con el plugin en un directorio concreto de la aplicación que está en ejecución y el plugin se cargaría automáticamente, inyectando en caliente los servicios que ofrece al que los necesite. Sin embargo, la pega de OSGI es es que es algo retorcido a la hora de desarrollar. Su objetivo es limitarnos para obligarnos a hacer el desarrollo modular y esas limitaciones a veces son un poco engorrosas.

Spring Boot por otro lado es muy sencillo de usar. Un par de anotaciones (@Autowired y @Service) y está todo apañado (por supuesto, siempre hay peguillas en el mundo real y casos extraños). Las pegas son que no permite el despliegue de plugins en caliente y que no obliga a desarrollo modular limitando visibilidad, por lo que tenemos que obligar a ese desarrollo modular a bases de subproyectos maven/gradle debidamente configurados.

Otra posible pega de Spring Boot es que en el arranque busca por todas las clases las anotaciones mencionadas para hacer el enganche. Si es un proyecto grande con muchas clases, el proceso de escaneo de todas las clases y sus anotaciones puede volverse lento. OSGI no tiene ese problema, porque cada jar, con código (o un xml si optamos por esa opción), pide o registra servicios en OSGI, no es OSGI el que se dedica a recorrer todo el código.

Y una ventaja clara de Spring Boot sobre OSGI es la cantidad de funcionalidades adicionales que de forma sencilla nos vienen de regalo. Por ejemplo, montar web services o soporte con bases de datos en Spring Boot es casi inmediato. En OSGI, aunque existe algo, es muy, muy engorroso de poner en marcha. Si conoces ambos frameworks, pero no has levantado nunca web services con ellos, en Spring Boot puedes buscar un tutorial y tener tu web service “hola mundo” en 10 minutos. Con OSGI, te puedes pasar una o dos semanas buscando los plugins que te dan soporte para crear web services y tenerlos funcionando, sin haber implementado todavía tu hola mundo. Spring Boot es seguramente más pesado, pero si quieres funcionalidad adicional es mucho más fácil.

¿Mi elección?

Para este proyecto que estoy empezando y que no tiene ningún requisito (ni visos de tenerlo) de despliegue de plugins en caliente, me he tirado por Spring Boot. Por su sencillez y porque voy a usar web services para comunicación entre consola y servidor, aunque sea java de escritorio.

Dec 10

Qué es Spring Boot

Hace unos meses estuve jugueteando con Spring Boot, pero el ponerme a hacer código a lo loco mirando la documentación y algunos tutoriales, no me dio una idea de lo que realmente es Spring Boot.

La idea de Spring Boot es que podamos hacer aplicaciones Spring, pero con cero configuración. No tenemos que hacer ningún fichero de configuración, ni ficheros XML. A Spring Boot, usando una herramienta propia, le decimos qué tipo de aplicación queremos (web, con jpa, con postgres, etc) y él solo nos genera una proyecto maven/gradle con todo lo necesario y que se autoconfigura en el arranque.

Por ejemplo, si decimos que queremos una aplicación web, Spring Boot automáticamente nos embebe un Tomcat y nos lo configura con el servlet de Spring. Por supuesto, si no nos gusta la configuración por defecto (no queremos Tomcat, por ejemplo), sí podemos cambiar cosas para usar jetty, jboss o el que nos guste.

¿y cómo hace esta magia Spring Boot?

Pues añadiendo en nuestro proyecto Maven/Gradle dependencias estilo "spring-boot-starter-****". Por ejemplo, si añadimos la dependencia "spring-boot-starter-web", es la que se encarga de añadir todo lo necesario para embeber un Tomcat y el que nos crea (sin que ni siquiera lo veamos en nuestro proyecto) el fichero web.xml de nuestra aplicación correctamente configurado para Spring. Si añadimos "spring-boot-starter-data-jpa" junto con la dependencia de algún driver de base de datos, como por ejemplo h2, es Spring Boot el que automáticamente en el arranque nos configurará automáticamente los DataSource para esa base de datos y todo lo necesario para acceder a esa base de datos usando JPA.

La magia de Spring Boot va incluso más allá. Una vez añadida la dependencia "spring-boot-starter-data-jpa" y la del driver de nuestra base de datos, sólo tenemos que crear nuestras clases de base de datos con las consabidas anotaciones @Entity, @Id, etc …  y una interfaz (adecuadamente anotada) que herede de la interfaz de Spring CrudRepository<MyBean, Long>, siendo MyBean la clase persistente que nos hemos creado y cuyo id es un Long. Y listo, no tenemos que implementar la interfaz, Spring Boot lo hace por nosotros en tiempo de ejecución, dándonos todos los métodos típicos de consulta/inserción/modificación y borrado de MyBean en base de datos.

Dentro de nuestro proyecto Spring Boot, en src/main/resources hay un fichero, en principo vacío, de nombre applicacion.properties. En ese fichero podemos poner properties propias de Spring Boot para cambiar las configuraciones por defecto de Spring Boot. Un ejemplo tiípico es cambiar el puerto por defecto 8080 de tomcat por otro. Basta añadir en ese fichero la linea server.port=8000 siendo 8000 el puerto que queremos en vez de 8080. Aquí tienes todas las posibles propiedades a poner y valores por defecto.

 

En fin, estoy con ello todavía, pero promete mucho y merece la pena echarle un ojo. Lo comentado aquí es un pequeño resumen de lo que se dice en este vídeo