Introdução ao Bootique

Introdução ao Bootique

1. Visão geral

Bootique é uma estrutura JVMcontainer-less de software livre muito leve, destinada a construir microsserviços escaláveis ​​de próxima geração. Ele é construído em cima do servidor Jetty integrado e oferece suporte total aREST manipuladores comjax-rs.

Neste artigo, mostraremos como construir um aplicativo da web simples usandoBootique.

2. Dependências do Maven

Vamos começar a usarBootique adicionando a seguinte dependência empom.xml:


    io.bootique.jersey
    bootique-jersey
    compile


    io.bootique
    bootique-test
    test

No entanto,Bootique também requer a declaração de algumas importaçõesBOM (“Bill of Material”). É por isso que a seção seguinte<dependencyManagement> precisa ser adicionada aopom.xml:


    
        
            io.bootique.bom
            bootique-bom
            0.23
            pom
            import
        
    

A versão mais recente deBootique está disponível emCentral Maven Repository.

Para construir um jar executável,Bootique depende demaven-shade-plugin. É por isso que também precisamos adicionar a configuração abaixo também:


    
        
            org.apache.maven.plugins
            maven-shade-plugin
        
    

3. Iniciando um aplicativo

A maneira mais simples de iniciar um aplicativoBootique é invocar o métodoBootique'sexec() a partir do método principal:

public class App {
    public static void main(String[] args) {
        Bootique.app(args)
          .autoLoadModules()
          .exec();
    }
}

However, this won’t start the embedded server. Uma vez que o código acima é executado, o seguinte log deve ser exibido:

NAME
      com.example.bootique.App

OPTIONS
      -c yaml_location, --config=yaml_location
           Specifies YAML config location, which can be a file path
           or a URL.

      -h, --help
           Prints this message.

      -H, --help-config
           Prints information about application modules and their
           configuration options.

      -s, --server
           Starts Jetty server.

Estes nada mais são do que os argumentos de programa disponíveis que vêm pré-agrupados comBootique.

Os nomes são autoexplicativos; portanto, para iniciar o servidor, precisamos passar o argumento–s ou–server e o servidor estará ativo e em execução nodefault port 8080.

4. Módulos

Bootique aplicativos são feitos com coleções de “módulos”. No termoBootique,“A module is a Java library that contains some code”, o que significa que trata cada serviço como um módulo. Ele usaGoogle Guice para injeção de dependência.

Para ver como funciona, vamos criar uma interface:

public interface HelloService {
    boolean save();
}

Agora, precisamos criar uma implementação:

public class HelloServiceImpl implements HelloService {

    @Override
    public boolean save() {
        return true;
    }
}

Existem duas maneiras pelas quais podemos carregar o módulo. O primeiro é usar a interfaceGuice'sModule, e o outro é usarBootique'sBQModuleProvider, que também é conhecido comoauto-loading.

4.1. Módulo Guice

Aqui, podemos usar a interfaceGuice'sModule para vincular instâncias:

public class ModuleBinder implements Module {

    @Override
    public void configure(Binder binder) {
        binder
          .bind(HelloService.class)
          .to(HelloServiceImpl.class);
    }
}

Assim que o módulo for definido, precisamos mapear este módulo personalizado para a instânciaBootique:

Bootique
  .app(args)
    .module(module)
    .module(ModuleBinder.class)
  .autoLoadModules()
  .exec();

4.2. BQModuleProvider (carregamento automático)

Aqui, tudo o que precisamos fazer é definir o fichário de módulo criado anteriormente comBQModuleProvider:

public class ModuleProvider implements BQModuleProvider {

    @Override
    public Module module() {
        return new ModuleBinder();
    }
}

A vantagem desta técnica é que não precisamos mapear nenhuma informação do módulo com a instânciaBootique.

Precisamos apenas criar um arquivo em/resources/META-INF/services/io.bootique.BQModuleProvidere escrever o nome completo doModuleProvider incluindo o nome do pacote eBootique cuidará do resto:

com.example.bootique.module.ModuleProvider

Agora, podemos usar a anotação@Inject para usar as instâncias de serviço no tempo de execução:

@Inject
HelloService helloService;

Uma coisa importante a notar aqui é que, uma vez que estamos usando o próprio mecanismo de DI deBootique, não precisamos usar a anotaçãoGuice @ImplementedBy para vincular as instâncias de serviço.

5. Endpoint REST

É simples criar endpoints REST usando a API JAX-RS:

@Path("/")
public class IndexController {

    @GET
    public String index() {
        return "Hello, example!";
    }

    @POST
    public String save() {
        return "Data Saved!";
    }
}

Para mapear os pontos de extremidade na própria instânciaJersey deBootique, precisamos definir umJerseyModule:

Module module = binder -> JerseyModule
  .extend(binder)
  .addResource(IndexController.class);

6. Configuração

Podemos fornecer informações de configuração personalizadas ou embutidas em um arquivo de propriedades baseado em YAML.

Por exemplo, se queremos iniciar o aplicativo em uma porta personalizada e adicionar um contexto padrão de URI ‘ola ', podemos usar a seguinte configuração YAML:

jetty:
    context: /hello
    connector:
        port: 10001

Agora, ao iniciar o aplicativo, precisamos fornecer a localização desse arquivo no parâmetro de configuração:

--config=/home/example/bootique/config.yml

7. Exploração madeireira

Out-of-the-boxBootique vem com um módulobootique-logback. Para usar este módulo, precisamos adicionar a seguinte dependência nopom.xml:


    io.bootique.logback
    bootique-logback

Este módulo vem com uma interfaceBootLogger com a qual podemos substituir para implementar o log personalizado:

Bootique.app(args)
  .module(module)
  .module(ModuleBinder.class)
    .bootLogger( new BootLogger() {
      @Override
      public void trace( Supplier args ) {
          // ...
      }
      @Override
      public void stdout( String args ) {
          // ...
      }
      @Override
      public void stderr( String args, Throwable thw ) {
          // ...
      }
      @Override
      public void stderr( String args ) {
          // ...
      }
}).autoLoadModules().exec();

Além disso, podemos definir as informações de configuração de registro no arquivoconfig.yaml:

log:
    level: warn
    appenders:
    - type: file
      logFormat: '%c{20}: %m%n'
      file: /path/to/logging/dir/logger.log

8. Teste

Para teste,Bootique vem com o módulobootique-test. Existem duas maneiras de testar um aplicativoBootique.

A primeira abordagem é a abordagem‘foreground', que faz com que todos os casos de teste sejam executados no thread de teste principal.

A outra é a abordagem‘background' que faz com que os casos de teste rodem em um pool de threads isolado.

O ambiente de 'primeiro plano' pode ser inicializado usandoBQTestFactory:

@Rule
public BQTestFactory bqTestFactory = new BQTestFactory();

O ambiente de 'background' pode ser inicializado usandoBQDaemonTestFactory:

@Rule
public BQDaemonTestFactory bqDaemonTestFactory = new BQDaemonTestFactory();

Quando a fábrica do ambiente estiver pronta, podemos escrever casos de teste simples para testar os serviços:

@Test
public void givenService_expectBoolen() {
    BQRuntime runtime = bqTestFactory
      .app("--server").autoLoadModules()
      .createRuntime();
    HelloService service = runtime.getInstance( HelloService.class );

    assertEquals( true, service.save() );
}

9. Conclusão

Neste artigo, mostramos como construir um aplicativo usando os módulos principais deBootique. Existem vários outros módulosBootique disponíveis, comobootique-jooq,bootique-kotlin,bootique-job, etc. A lista completa de módulos disponíveis está disponívelhere.

Como sempre, o código-fonte completo está disponívelover on GitHub.