Ontem, deixei você com um código aproximado que iniciou um servidor Ratpack e usou um repositório Couchbase síncrono, deixando o RxJava parte fora. Pretendo corrigir isso hoje e também falar mais sobre o Ratpack. Ainda não vou lhe mostrar uma API REST completa, mas chegaremos lá :)
Em minha exemplo anteriorComo eu estava fazendo isso, estava instanciando um novo objeto Repository toda vez que precisava de um. Devido à maneira como isso era feito, também abria uma nova conexão Cluter a cada vez. Há maneiras de evitar isso com o Ratpack, como o registro.
Registro do Ratpack
O pacote de ratos registro é um armazenamento de objetos disponíveis no contexto de um manipulador. Por padrão, você obtém um registro vazio. Você pode adicionar instâncias de objetos. Esses objetos são recuperados por tipo. Eles não podem ser nomeados. Isso significa que você só pode ter um objeto por tipo no seu registro. Isso pode parecer estranho, mas na verdade é muito útil ao codificar em Groovy. Dê uma olhada em este exemplo por exemplo. É muito fácil de ler.
No meu código, estou usando apenas o objeto Repository para acessar o Couchbase, portanto, é esse objeto que colocarei no registro:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
público estático vazio principal(Cordas... argumentos) lançamentos Exceção { RatpackServer.iniciar(servidor -> servidor .registroDe(registro ->registro.adicionar(CouchbaseCluster.criar().openBucket().repositório())) .manipuladores(cadeia -> cadeia.caminho("create" (criar), ctx -> { EntidadeDocumento<Usuário> documento = EntidadeDocumento.criar(novo Usuário("ldoguin", 31, "Laurent", "Doguin")); Bloqueio.obter(() -> { Repositório repo = ctx.obter(Repositório.classe); retorno repo.upsert(documento); }).então(entidadeDoc -> ctx.renderizar("OK")); }).caminho("obter", ctx -> { Bloqueio.obter(() -> { Repositório repo = ctx.obter(Repositório.classe); EntidadeDocumento<Usuário> ldoguin = repo.obter("ldoguin", Usuário.classe); retorno ldoguin; }).então(usuário -> ctx.renderizar(usuário.conteúdo().toString())); }))); } |
Como você pode ver, recuperar um objeto do registro é fácil. Você precisa chamar o método get e fornecer o tipo do objeto como parâmetro.
Isso funciona muito bem para aplicativos realmente leves. Pode ficar muito mais sério usando o Módulo Guice.
Módulos Guice
O Ratpack não é apenas um simples servidor da Web assíncrono e sem bloqueio. Ele também é um conjunto abrangente de módulos que permite adicionar novos recursos de forma elegante. O registro pode ser facilmente estendido usando uma estrutura DI. O mais comumente usado no Ratpack é o Guice, mas você pode usar o Spring ou qualquer outro suportado. Para ativar o módulo Guice, você precisa adicionar uma linha em seu arquivo build.gradle
na dependência:
1 2 3 4 5 |
dependências { compilar pacote de rato.dependência("guice"), "com.couchbase.client:java-client:2.2.5" } |
O Ratpack tem uma ótima integração com o Gradle. Todos os módulos do Ratpack podem ser adicionados de forma tão simples quanto isso. Agora que o suporte ao Guice está ativado, posso começar adicionando uma configuração de registro adequada. Adicionarei instâncias de Bucket e Repositório ao meu registro. A primeira etapa é criar um módulo Guice adicionando uma classe que estende a classe Guice's AbstractModule.
1 2 3 4 5 6 7 8 9 10 |
público classe Configuração se estende AbstractModule { protegida vazio configurar() { CouchbaseCluster cc = CouchbaseCluster.criar(); Balde balde = cc.openBucket(); vincular(Balde.classe).toInstance(balde); vincular(Repositório.classe).toInstance(balde.repositório()); } } |
Depois que essa classe for criada, preciso adicioná-la ao meu registro do Ratpack da seguinte forma:
1 2 |
RatpackServer.iniciar(servidor -> servidor.registro(Guice.registro(b -> b.módulo(Configuração.classe))) |
E agora tenho uma configuração mais limpa para minhas futuras injeções de instância. Mas tudo ainda é síncrono. Portanto, vou alterar essa configuração para usar a versão assíncrona do Bucket e do Repositório:
1 2 3 4 5 6 7 8 9 10 |
público classe Configuração se estende AbstractModule { protegida vazio configurar() { CouchbaseCluster cc = CouchbaseCluster.criar(); Balde balde = cc.openBucket(); vincular(AsyncBucket.classe).toInstance(balde.assíncrono()); vincular(AsyncRepository.classe).toInstance(balde.repositório().assíncrono()); } } |
A próxima etapa aqui é garantir que eu possa usar meus observáveis RxJava no Ratpack. E, como a vida é bela (alguns diriam bootiful), existe um módulo para isso.
Módulo RxJava
O Módulo RxJava tem como objetivo criar uma ponte entre o Rx Observables e o Ratpack Promises. Como o módulo Guice, ele pode ser ativado facilmente com a adição da dependência apropriada:
1 2 3 4 5 6 |
dependências { compilar pacote de rato.dependência("guice"), pacote de rato.dependência("rx"), "com.couchbase.client:java-client:2.2.5" } |
Você também precisa inicializar o módulo uma vez por JVM. Portanto, o melhor lugar para executar a inicialização aqui é antes do init do servidor Ratpack. Isso pode ser feito chamando:
1 2 |
RxRatpack.inicializar(); |
O objeto RxRatpack tem métodos estáticos para fazer a conversão Observable/Promise. O mais simples funciona da seguinte forma:
1 2 |
RxRatpack.promessa(repo.upsert(documento)).então(entidadeDoc -> ctx.renderizar("OK")); |
Vale a pena mencionar que, como um Observable pode conter de zero a qualquer elemento, ele é transformado em uma lista quando fornecido ao resultado da Promise. Portanto, se você tiver apenas um objeto em seu Observable, precisará obter explicitamente o primeiro elemento da lista.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
público estático vazio principal(Cordas... argumentos) lançamentos Exceção { RxRatpack.inicializar(); RatpackServer.iniciar(servidor -> servidor.registro(Guice.registro(b -> b.módulo(Configuração.classe))) .manipuladores(cadeia -> cadeia.caminho("create" (criar), ctx -> { EntidadeDocumento<Usuário> documento = EntidadeDocumento.criar(novo Usuário("ldoguin", 31, "Laurent", "Doguin")); AsyncRepository repo = ctx.obter(AsyncRepository.classe); RxRatpack.promessa(repo.upsert(documento)).então(entidadeDoc -> ctx.renderizar("OK")); }).caminho("obter", ctx -> { AsyncRepository repo = ctx.obter(AsyncRepository.classe); RxRatpack.promessa(repo.obter("ldoguin", Usuário.classe)) .então(usuários -> ctx.renderizar(usuários.obter(0).conteúdo().toString())); }))); } |
O que mudou desde a versão anterior foi o uso de um registro baseado em Guice para DI e as chamadas do Couchbase agora são todas assíncronas. Agora estou em uma boa posição para começar a criar uma API REST adequada para meus usuários. E esse é o tópico para outra postagem no blog.