Con el auge de los microservicios y el modelo de facturación de los servicios en cloud, nos vemos en la necesidad de analizar los entornos en los que se ejecutan nuestas aplicaciones. Vamos a analizar los «Micro» Frameworks de Java más populares para el desarrollo de capas de servicios.
Tradicionalmente, las aplicaciones web Java han sido desplegadas con su correspondiente servidor de aplicaciones; un Tomcat, un JBoss (Wildfly), un Glassfish (Payara) o cualquier otro contenedor. Estos contenedores aportaban la funcionalidad necesaria para el acceso desde la red a dichas aplicaciones.
Desgraciadamente, con esos servidores de aplicaciones vienen asociados diversos inconvenientes, principalmente que no siempre sea transparente llevar nuestras aplicaciones de un contenedor a otro porque la forma de configurarlos es diferente o porque generan errores de dependencias compartidas con nuestras propias aplicaciones. Por alguna razón, los distintos contenedores web han ido adentrándose en el terreno de forzar a que las aplicaciones que corren en ellos queden atadas a su implementación.
Con el auge del mundo de los microservicios todos esos contenedores han encontrado un nuevo «problema» asociado, cuando nuestra funcionalidad es pequeña, que es lo esperado en un microservicio, el contenedor se convierte más en una carga de memoria y CPU en lugar de una ayuda. No parece buena idea un pequeño servicio que realice una pequeña función por ejemplo de tratamiento de imágenes se vea sobrecargado por un contenedor de aplicaciones que consuma mucha más memoria que la funcionalidad misma.
Consumo de memoria en Standby:
Tomcat: Mem: 127Mb
Jboss Wildfly: Mem: 315Mb
Payara Micro: 371Mb
Debido a estos consumos muchas veces innecesarios en el escenario de microservicios, han ido apareciendo soluciones autocontenidas que permiten que las aplicaciones puedan exponer sus servicios sin la sobrecarga de los contenedores.
Sin desmerecer a los contenedores de aplicaciones que claramente tienen un escenario de uso, vamos a analizar algunas de estas soluciones «micro» orientadas específicamente al mundo de los microservicios mediante un simple servicio de echo:
- SparkJava
- Javalin
- Ninja
- Micronaut
- Dropwizard
- SpringBoot
- Rapidoid
1. SparkJava
Website: http://sparkjava.com/
Repositorio github: https://github.com/perwendel/spark
Documentación: 7 / 10
Boot Time: 0.3s
Peticiones/segundo: 13500
El primero de nuestros frameworks de Java, Sparkjava es un framework web ligero, tan solo nos da una pequeña y muy ligera capa de abstracción sobre un servidor Jetty, dejando bajo nuestra responsabilidad la decisión sobre el resto de librerías que nuestra aplicación necesite utilizar. Pese a no ser un framework que nos ofrezca grandes funcionalidades, nos asegura que difícilmente tendremos un problema de compatibilidad entre las librerías que usamos y las librerías incluidas en el framework.
Por otra parte, al ser tan liviano requiere cierto procesamiento manual de las peticiones, pareciéndose más a un servlet que a un framework completo.
public class SparkServer {
private Gson gson=new Gson();
public static final void main(String[] args){
new SparkServer();
}
private SparkServer(){
port(8080);
post("/echo","application/json", this::echo);
}
private Object echo(Request request, Response response) {
Message input=gson.fromJson(request.body(), Message.class);
input.setValue("echo "+input.getValue());
return gson.toJson(input);
}
public void stop(){
Spark.stop();
}
}
A favor:
- Inicio muy rápido
- Tamaño de compilado muy pequeño
- Comunidad activa
En contra:
- Falta de funcionalidades integradas
2. Javalin
Website: https://javalin.io/
Repositorio github: https://github.com/tipsy/javalin
Documentacion: 7 / 10
Boot Time: 0.3 s
Peticiones/segundo : 15000
Javalin es el primo hermano de SparkJava, de hecho es un fork del mismo proyecto sobre el que se han añadido funcionalidades como control de sesiones, validación, soporte transparente a serialización de objetos json, al mismo tiempo que se ha reducido la cantidad de código del proyecto original.
public class JavalinService {
private Javalin app;
public static final void main(String[] args){
new JavalinService();
}
private JavalinService(){
app = Javalin.create().start(8080);
app.post("/echo", this::echo);
}
private void echo(Context ctx) {
Message item = ctx.bodyAsClass(Message.class);
item.setValue("echo "+item.getValue());
ctx.json(item);
}
public void stop() {
app.stop();
}
}
A favor:
- Inicio muy rápido.
- Tamaño de compilado muy pequeño.
- Gran velocidad de procesado de peticiones
En contra:
- Falta de funcionalidades integradas
- Poca comunidad
3. Ninja
Website: https://www.ninjaframework.org
Repositorio github: https://github.com/ninjaframework/ninja
Documentación: 4 / 10
Boot Time: 1s
Peticiones/segundo: 10000
Ninja es un framework integrado, es decir, no incluye únicamente la capa de servicios sino también vistas, jpa, o inyección de dependencias. Desgraciadamente está poco documentado y su guía de usuario nos invita a crear un proyecto a partir de un arquetipo maven, lo que siempre es una señal de alarma.
Por otra parte, la estructura del proyecto generado no es estándar, generándose ficheros de recursos, configuración y vistas fuera del directorio maven estándar; si estamos acostumbrados a cierto orden puede resultar molesto.
public class Routes implements ApplicationRoutes {
@Override
public void init(Router router) { router.POST().route("/echo").with(ApplicationController::echo);
}
}
@Singleton
public class ApplicationController {
public static Result echo(Message item) {
item.setValue("echo "+item.getValue());
return Results.json().render(item);
}
}
A favor:
- Modo SuperDev para hacer rápidos despliegues durante el desarrollo
En contra:
- Lentitud en el procesamiento de peticiones.
- Estructura no estándar de proyecto.
- Ofrece un ecosistema muy cerrado, con dificultades para migrarlo.
4. Micronaut
Website: https://micronaut.io/
Repositorio Github: https://github.com/micronaut-projects/micronaut-core
Documentación: 8 / 10
Boot time: 1.3s
Peticiones/segundo: 13000
Micronaut es uno de los frameworks de Java integrados para microservicios que busca principalmente la facilidad de implementar tests y la clara orientación a servicios cloud, dando soporte a gestión de errores y reintentos.
Por otra parte, hemos encontrado algunas dificultades a la hora de probarlo, arrojándonos errores poco claros y no excesivamente documentados debidos al procesamiento de las anotaciones.
@Controller("/")
public class EchoController {
@Post(uri = "/echo", produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
public Message echo(Message message) {
message.setValue("echo "+message.getValue());
return message;
}
}
A favor:
- Alto rendimiento en el procesado de peticiones.
- Facilidad de configuración.
En contra:
- Es un framework relativamente pesado.
5. Dropwizard
Website: https://www.dropwizard.io/en/latest/
Repositorio Github: https://github.com/dropwizard/dropwizard
Documentación: 7 / 10
Boot time: 1.5s
Peticiones/segundo : 11000
Dropwizard es un framework integrado con Jetty/Jersey como centro de su capa de servicios y otras librerías de utilidad no acopladas y modulares, como JDBI, Guava o FreeMarker
@Path("/")
public class MessageController {
@POST @Path("/echo") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response echo(Message message) throws IOException {
message.setValue("echo "+message.getValue());
return Response.ok(message).build();
}
}
A favor:
- Muy ligero en consumo de memoria .
- Framework bien documentado.
- Las librerías que lo componen son estándar (Jersey, JDBI).
- Desarrollo muy activo.
En contra:
- No es muy sencillo implementar la seguridad, existe soporte para autenticación pero no para autorización
6. SpringBoot
Website: https://spring.io/projects/spring-boot
Repositorio github: https://github.com/spring-projects/spring-boot
Documentación: 10 / 10
Boot time: 2s
Peticiones/segundo: 15000
Dentro de los frameworks de Java, SpringBoot es el más usado en el entorno empresarial. Ofrece cientos de módulos que van desde desde la capa de presentación al acceso a base de datos pasando por el procesamiento distribuido. SpringBoot se beneficia lógicamente de todo lo desarrollado desde los orígenes de Spring, esto es, la inyección de dependencia, y las facilidades de integración con productos de terceros.
Por otra parte, igual que Spring Framework requería de muchos recursos de memoria y CPU, igual le sucede a SpringBoot
A favor:
- Muy documentado.
- Ampliamente adoptado por la comunidad.
- Múltiples librerías igualmente documentadas.
- Incluye todas las ventajas del framework Spring.
- Buen soporte para seguridad, tanto autenticación como autorización.
En contra:
- Compilados bastante grandes.
- Lentitud en el arranque.
- Alto consumo de memoria.
@RestController
@EnableAutoConfiguration
@ComponentScan
public class TextApplication {
public static void main(String[] args) {
SpringApplication.run(TextApplication.class);
}
@PostMapping(value = "/echo",consumes = MediaType.APPLICATION_JSON_VALUE,produces = MediaType.APPLICATION_JSON_VALUE)
public Message handle(Message message) {
message.setValue("output");
return message;
}
}
7. Rapidoid
Website: https://www.rapidoid.org/
Repositorio Github: https://github.com/rapidoid/rapidoid
Documentación: 5 / 10
Boot time: 0.9 s
Peticiones/segundo: 17000
Rapidoid es casi un desconocido, es un framework que ofrece tanto una capa rest como un motor de plantillas para la capa de presentación. Su principal ventaja es la velocidad de procesado de las peticiones, siendo la más alta de todas las analizadas.
A favor:
- Alta velocidad de procesado de peticiones, con mínimo impacto en memoria.
- Tamaño mínimo de despliegue.
- Mínima cantidad de código fuente.
En contra:
- Uso casi exclusivo de JSON.
- Consumo de memoria en standby
- Poco documentado
- Pocas funcionalidades incluidas
- Poco movimiento en su repositorio
public class Rapidoid {
public static void main(String[] args){
On.post("/echo").json((Message message)->{message.setValue("echo "+message.getValue());return message;});
}
}
Resumen:




Conclusión
A la hora de elegir con cuál del los frameworks de Java nos quedamos para desplegar como microservicios es necesario tener muchos factores en cuenta.
La memoria es un factor tan importante como la velocidad de proceso, ya que ésta normalmente afecta profundamente en el coste de los servidores. De forma general será más fácil adaptar código existente a microservicios apoyándonos en frameworks más completos, como SpringBoot o Dropwizard, mientras que si estamos diseñando un sistema desde cero, diseñando todo en base a microservicios, nos será más cómodo tomar como base un framework ligero, como Spark, (o si nos sentimos muy valientes como Rapidoid) e ir añadiendo nuestras dependencias sobre ellos.