Cuando la tarea a ejecutar por el servidor es más pesada, como servir una imagen por ejemplo, la programación
reactiva nos permite optimizar su ejecución. Por ejemplo, a continuación se muestra un Controller que permite descargar
un Gif. En lugar de leer todo el fichero y enviarlo como un array de bytes en la misma petición lo que va a usar es
un Flowable
Un objeto del tipo Flowable
nos va a permitir ir enviando bloques de información al cliente según vayamos obteniéndola.
Una vez completada la tarea notificaremos al Flowable
que ya se ha completado y esto terminará el diálogo con el
cliente:
@Controller("/test")
class FileController{
@Get(value = "/{file}", produces = MediaType.IMAGE_GIF)
Flowable<byte[]> image(@PathVariable String file) {
Flowable.create({ emitter ->
new File(file).withInputStream{ inputStream ->
int size=1024
byte[]buff = inputStream.readNBytes(size)
while( buff.length == size){
emitter.onNext(buff)
buff = inputStream.readNBytes(size)
}
emitter.onNext(buff)
emitter.onComplete()
}
}, BackpressureStrategy.BUFFER)
}
}
En este ejemplo, el cliente solicita un fichero y lo que devuelve el controller es un objeto Flowable
. Cuando el subsistema
se encuentre preparado se subscribirá a este y le proporcionará un objeto emitter
el cual nos va a servir para ir
enviando "chunks" de información:
-
abrimos el fichero y vamos leyendo bloques de 1024 bytes
-
se los vamos pasando al emitter mediante onNext
. El subsistema es el encargado de ir enviándolos a su vez usando
la estrategia que hayamos especificado (BUFFER en este caso)
-
una vez enviados los últimos bytes notificamos que hemos terminado con onComplete
Mediante esta técnica podemos servir ficheros pesados a multitud de clientes sin bloquear las llamadas. (He empleado
este bot en una página donde podías descargar las imágenes de tráfico de la DGT y una simple aplicación era capaz de
servir cientos de imágenes de forma fluida)