Introduction à Bootique
1. Vue d'ensemble
Bootique est un framework JVMcontainer-less open source très léger visant à créer des micro-services évolutifs de nouvelle génération. Il est construit sur le serveur Jetty intégré et prend entièrement en charge les gestionnairesREST avecjax-rs.
Dans cet article, nous allons montrer comment créer une application Web simple à l'aide deBootique.
2. Dépendances Maven
Commençons à utiliserBootique en ajoutant la dépendance suivante dans lespom.xml:
io.bootique.jersey
bootique-jersey
compile
io.bootique
bootique-test
test
Cependant,Bootique nécessite également de déclarer quelques importations deBOM (“Bill of Material”). C'est pourquoi la section<dependencyManagement> suivante doit être ajoutée dans lespom.xml:
io.bootique.bom
bootique-bom
0.23
pom
import
La dernière version deBootique est disponible enCentral Maven Repository.
Pour créer un fichier jar exécutable,Bootique s'appuie surmaven-shade-plugin. C’est pourquoi nous devons également ajouter la configuration ci-dessous:
org.apache.maven.plugins
maven-shade-plugin
3. Démarrer une application
Le moyen le plus simple de démarrer une applicationBootique est d'appeler la méthodeexec() deBootique à partir de la méthode principale:
public class App {
public static void main(String[] args) {
Bootique.app(args)
.autoLoadModules()
.exec();
}
}
However, this won’t start the embedded server. Une fois, le code ci-dessus est exécuté, le journal suivant doit être affiché:
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.
Ce ne sont rien d'autre que les arguments de programme disponibles pré-fournis avecBootique.
Les noms sont explicites; par conséquent, pour démarrer le serveur, nous devons passer l'argument–s ou–server et le serveur sera opérationnel sur lesdefault port 8080.
4. Modules
Les applicationsBootique sont faites avec des collections de «modules». Dans le termeBootique“A module is a Java library that contains some code”, cela signifie qu'il traite chaque service comme un module. Il utiliseGoogle Guice pour l'injection de dépendances.
Pour voir comment cela fonctionne, créons une interface:
public interface HelloService {
boolean save();
}
Maintenant, nous devons créer une implémentation:
public class HelloServiceImpl implements HelloService {
@Override
public boolean save() {
return true;
}
}
Il existe deux manières de charger le module. La première consiste à utiliser l'interfaceModule deGuice et l'autre à utiliserBQModuleProvider deBootique, également connu sous le nom deauto-loading.
4.1. Module Guice
Ici, nous pouvons utiliser l'interfaceModule deGuice pour lier des instances:
public class ModuleBinder implements Module {
@Override
public void configure(Binder binder) {
binder
.bind(HelloService.class)
.to(HelloServiceImpl.class);
}
}
Une fois le module défini, nous devons mapper ce module personnalisé à l'instanceBootique:
Bootique
.app(args)
.module(module)
.module(ModuleBinder.class)
.autoLoadModules()
.exec();
4.2. BQModuleProvider (chargement automatique)
Ici, tout ce que nous avons à faire est de définir le module-binder créé précédemment avecBQModuleProvider:
public class ModuleProvider implements BQModuleProvider {
@Override
public Module module() {
return new ModuleBinder();
}
}
L’avantage de cette technique est que nous n’avons pas besoin de mapper les informations de module avec l’instanceBootique.
Nous avons juste besoin de créer un fichier dans/resources/META-INF/services/io.bootique.BQModuleProvider et d'écrire le nom complet desModuleProvider avec le nom du package etBootique s'occupera du reste:
com.example.bootique.module.ModuleProvider
Maintenant, nous pouvons utiliser l'annotation@Inject pour utiliser les instances de service au moment de l'exécution:
@Inject
HelloService helloService;
Une chose importante à noter ici est que puisque nous utilisons le mécanisme DI deBootique, nous n'avons pas besoin d'utiliser l'annotationGuice @ImplementedBy pour lier les instances de service.
5. Point de terminaison REST
Il est simple de créer des points de terminaison REST à l’aide de l’API JAX-RS:
@Path("/")
public class IndexController {
@GET
public String index() {
return "Hello, example!";
}
@POST
public String save() {
return "Data Saved!";
}
}
Pour mapper les points de terminaison dans l'instance deJersey deBootique, nous devons définir unJerseyModule:
Module module = binder -> JerseyModule
.extend(binder)
.addResource(IndexController.class);
6. Configuration
Nous pouvons fournir des informations de configuration intégrées ou personnalisées dans un fichier de propriétés basé sur YAML.
Par exemple, si nous souhaitons démarrer l’application sur un port personnalisé et ajouter un contexte URI par défaut, «Bonjour», nous pouvons utiliser la configuration YAML suivante:
jetty:
context: /hello
connector:
port: 10001
Maintenant, lors du démarrage de l'application, nous devons fournir l'emplacement de ce fichier dans le paramètre de configuration:
--config=/home/example/bootique/config.yml
7. Enregistrement
LeBootique prêt à l'emploi est livré avec un modulebootique-logback. Pour utiliser ce module, nous devons ajouter la dépendance suivante dans lespom.xml:
io.bootique.logback
bootique-logback
Ce module est livré avec une interfaceBootLogger avec nous pouvons remplacer pour implémenter la journalisation personnalisée:
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();
De plus, nous pouvons définir les informations de configuration de journalisation dans le fichierconfig.yaml:
log:
level: warn
appenders:
- type: file
logFormat: '%c{20}: %m%n'
file: /path/to/logging/dir/logger.log
8. Essai
Pour les tests,Bootique est fourni avec le modulebootique-test. Il y a deux façons de tester une applicationBootique.
La première approche est l'approche‘foreground' qui fait que tous les cas de test s'exécutent sur le thread de test principal.
L'autre est l'approche‘background' qui fait exécuter les cas de test sur un pool de threads isolé.
L'environnement «de premier plan» peut être initialisé à l'aide deBQTestFactory:
@Rule
public BQTestFactory bqTestFactory = new BQTestFactory();
L'environnement «d'arrière-plan» peut être initialisé à l'aide deBQDaemonTestFactory:
@Rule
public BQDaemonTestFactory bqDaemonTestFactory = new BQDaemonTestFactory();
Une fois que l'usine d'environnement est prête, nous pouvons écrire des cas de test simples pour tester les services:
@Test
public void givenService_expectBoolen() {
BQRuntime runtime = bqTestFactory
.app("--server").autoLoadModules()
.createRuntime();
HelloService service = runtime.getInstance( HelloService.class );
assertEquals( true, service.save() );
}
9. Conclusion
Dans cet article, nous avons montré comment créer une application à l'aide des modules principaux deBootique. Il existe plusieurs autres modulesBootique disponibles commebootique-jooq,bootique-kotlin,bootique-job, etc. La liste complète des modules disponibles est disponiblehere.
Comme toujours, le code source complet est disponibleover on GitHub.