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.