{"id":1326,"date":"2021-10-15T12:00:52","date_gmt":"2021-10-15T10:00:52","guid":{"rendered":"https:\/\/www.loicmathieu.fr\/wordpress\/?p=1326"},"modified":"2023-01-24T12:49:09","modified_gmt":"2023-01-24T11:49:09","slug":"quarkus-tip-selectionner-un-bean-au-runtime","status":"publish","type":"post","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/quarkus-tip-selectionner-un-bean-au-runtime\/","title":{"rendered":"Quarkus Tip : S\u00e9l\u00e9ctionner un bean au runtime"},"content":{"rendered":"<p>Lors du d\u00e9veloppement d&rsquo;une application, il est tr\u00e8s fr\u00e9quent d&rsquo;avoir plusieurs impl\u00e9mentations d&rsquo;un service, et de devoir s\u00e9lectionner l&rsquo;une o\u00f9 l&rsquo;autre en fonction de l\u2019environnement sur lequel elle est d\u00e9ploy\u00e9e.<\/p>\n<p>Un exemple classique : un service qui appelle une API d&rsquo;un partenaire externe qu&rsquo;on veut appeler uniquement en production, et donc mocker sur les environnements de d\u00e9veloppement et de test \/ UAT \/ staging.<\/p>\n<p>Quarkus essaye de d\u00e9porter au build time, via son plugin Maven ou Gradle, le plus de choses possibles. Entre autre, il d\u00e9couvre les beans CDI au build time, et ne va instancier que ceux n\u00e9cessaire au runtime.<\/p>\n<p>Pour pouvoir s\u00e9lectionner un bean, on a la possibilit\u00e9 d&rsquo;utiliser l&rsquo;annotation <a title=\"@IfBuildProfile\" href=\"https:\/\/quarkus.io\/guides\/cdi-reference#enabling-beans-for-quarkus-build-profile\" target=\"_blank\" rel=\"noopener\"><a>@IfBuildProfile<\/code>code&gt;@IfBuildProfile&lt;\/code<\/a><\/a>, l&rsquo;annotation <a title=\"@IfBuildPropertiy\" href=\"https:\/\/quarkus.io\/guides\/cdi-reference#enabling-beans-for-quarkus-build-properties\" target=\"_blank\" rel=\"noopener\"><a>@IfBuildProperty<\/code>code&gt;@IfBuildProperty&lt;\/code<\/a><\/a>, ou les <a title=\"alternatives CDI\" href=\"https:\/\/quarkus.io\/guides\/cdi-reference#declaring-selected-alternatives\" target=\"_blank\" rel=\"noopener\">alternatives CDI<\/a>. Mais ces solutions vont s\u00e9lectionner le bean au build time! Cel\u00e0 permet d&rsquo;avoir un bean diff\u00e9rent pour les tests unitaires ou le dev mode mais pas une fois que l&rsquo;application a \u00e9t\u00e9 construite. Pour utiliser ce m\u00e9canisme pour s\u00e9lectionner un bean diff\u00e9rent sur un environement UAT\/staging et sur la prod, il faudrait builder plusieurs packages de l&rsquo;application.<\/p>\n<p>S\u00e9lectionner un bean au runtime reste possible en utilisation une <code>Instance<\/code> CDI, cela n\u00e9cessite quelques lignes de code.<\/p>\n<p>Voici comment faire.<\/p>\n<p><strong>Etape 1<\/strong> : ajouter une propri\u00e9t\u00e9 dans votre <code>application.properties<\/code><\/p>\n<pre>service.implementation-name=mock\n<\/pre>\n<p><strong>Etape 2<\/strong> : annoter vos deux impl\u00e9mentations avec un qualifier CDI, ici on utilisera <a>@Named<\/code>code&gt;@Named&lt;\/code<\/a> mais Quarkus propose aussi <a>@Identifier<\/code>code&gt;@Identifier&lt;\/code<\/a>.<\/p>\n<pre>@ApplicationScoped\n@Named(\"mock\")\npublic class MockService implements RemoteService {\n    \/\/ ....\n}\n<\/pre>\n<pre>@ApplicationScoped\n@Named(\"real\")\npublic class RealService implements RemoteService {\n    \/\/ ....\n}\n<\/pre>\n<p><strong>Etape 3<\/strong> : dans la classe utilisant votre service, s\u00e9lectionner le bean au d\u00e9marrage de l&rsquo;application en vous basant sur la configuration de l&rsquo;application.<\/p>\n<pre>@Path(\"\/api\")\npublic class MyEndpoint {\n    @ConfigProperty(name=\"service.implementation-name\") String implementationName;\n    @Inject InstanceremoteServiceInstance;\n\n    private RemoteService remoteService;\n\n    @PostConstruct\n    void init() {\n        remoteService = remoteServiceInstance\n            .select(NamedLiteral.of(implementationName)).get();\n    }\n\n    \/\/ ...\n}\n<\/pre>\n<p><strong>MISE A JOUR<\/strong> : Martin Kouba (merci \u00e0 lui) a propos\u00e9 une impl\u00e9mentation plus courte et clair, via injection dans le constructeur (ce que, \u00e0 ma grand honte, je ne suis pas du tout familier). Je vous met donc ci-dessous une \u00e9tape 3 avec un code simplifi\u00e9 :<\/p>\n<pre>@Path(\"\/api\")\npublic class MyEndpoint {   \n   private final RemoteService remoteService;\n\n   MyEndpoint(@ConfigProperty(name=\"service.implementation-name\") String implName, \n         Instance remoteServiceInstance) {\n     remoteService = remoteServiceInstance.select(NamedLiteral.of(implName)).get();\n   }\n\n    \/\/ ...\n}\n<\/pre>\n<p><strong>Attention<\/strong> : les d\u00e9finitions (metadata) deux beans <code>MockService<\/code> et <code>RemoteService<\/code> seront cr\u00e9\u00e9es et resterons en m\u00e9moire tout au long de la vie de votre application, m\u00eame si uniquement l&rsquo;un des deux sera utilis\u00e9. Elles ne seront pas supprim\u00e9es automatiquement par Arc, l&rsquo;impl\u00e9mentation CDI de Quarkus, via son m\u00e9canisme de <a title=\"suppression de bean inutilis\u00e9\" href=\"https:\/\/quarkus.io\/guides\/cdi-reference#remove_unused_beans\" target=\"_blank\" rel=\"noopener\">suppression de bean inutilis\u00e9<\/a>. Les beans quand \u00e0 eux, s&rsquo;ils utilisent un scope normal, seront cr\u00e9\u00e9 de mani\u00e8re <a href=\"https:\/\/quarkus.io\/guides\/cdi-reference#lazy_by_default\" target=\"_blank\" rel=\"noopener\">lazy<\/a>.<\/p>\n<p>Conclusion : m\u00eame si s\u00e9lectionner un bean au runtime va \u00e0 l&rsquo;encontre de la philosophie de Quarkus, c&rsquo;est bien souvent une n\u00e9cessit\u00e9 et cela reste possible via quelques lignes de code. Comme c&rsquo;est quelque chose de classique, je vais \u00e9voquer le point avec la communaut\u00e9 Quarkus pour qu&rsquo;on trouve quelque chose de plus pratique, stay tuned ;)<\/p>\n<p><strong>MISE A JOUR<\/strong> : J&rsquo;ai depuis \u00e9voqu\u00e9 le point avec la communaut\u00e9 Quarkus et une solution plus pratique que l&rsquo;utilisation de <code>instance.select()<\/code> a \u00e9t\u00e9 impl\u00e9ment\u00e9e gr\u00e2ce aux annotations <a>@LookupIfProperty<\/code>code&gt;@LookupIfProperty&lt;\/code<\/a> et <a>@LookupUnlessProperty<\/code>code&gt;@LookupUnlessProperty&lt;\/code<\/a> qui permettent d&rsquo;ajouter, pour chaque bean, une condition pour leur s\u00e9lection en fonction d&rsquo;une propri\u00e9t\u00e9 de configuration.<\/p>\n<p>On peut donc remplacer les \u00e9tapes 2 et 3 pr\u00e9c\u00e9dentes par celles-ci :<\/p>\n<p><strong>Etape 2<\/strong> : annoter vos deux impl\u00e9mentations avec <a>@LookupIfProperty<\/code>code&gt;@LookupIfProperty&lt;\/code<\/a>.<\/p>\n<pre>@ApplicationScoped\n@LookupIfProperty(name = \"service.implementation-name\", stringValue = \"mock\")\npublic class MockService implements RemoteService {\n    \/\/ ....\n}\n<\/pre>\n<pre>@ApplicationScoped\n@LookupIfProperty(name = \"service.implementation-name\", stringValue = \"real\")\npublic class RealService implements RemoteService {\n    \/\/ ....\n}\n<\/pre>\n<p><strong>Etape 3<\/strong> : dans la classe utilisant votre service, le bean doit \u00eatre obtenu au d\u00e9marrage via la m\u00e9thode <code>get()<\/code> de l&rsquo;instance. La pr\u00e9sence de l&rsquo;annotation <a>@LookupIfProperty<\/code>code&gt;@LookupIfProperty&lt;\/code<\/a> sur les deux impl\u00e9mentations fera que seul le bean de type <code>MockService<\/code> sera cr\u00e9\u00e9 car la valeur de la propri\u00e9t\u00e9 <code>service.implementation-name<\/code> utilis\u00e9 dans son instance de <a>@LookupIfProperty<\/code>code&gt;@LookupIfProperty&lt;\/code<\/a> est <code>mock<\/code>.<\/p>\n<pre>@Path(\"\/api\")\npublic class MyEndpoint {\n    @Inject InstanceremoteServiceInstance;\n\n    private RemoteService remoteService;\n\n    @PostConstruct\n    void init() {\n        remoteService = remoteServiceInstance.get();\n    }\n\n    \/\/ ...\n}\n<\/pre>\n<p><\/p>","protected":false},"excerpt":{"rendered":"<p>Lors du d\u00e9veloppement d&rsquo;une application, il est tr\u00e8s fr\u00e9quent d&rsquo;avoir plusieurs impl\u00e9mentations d&rsquo;un service, et de devoir s\u00e9lectionner l&rsquo;une o\u00f9 l&rsquo;autre en fonction de l\u2019environnement sur lequel elle est d\u00e9ploy\u00e9e. Un exemple classique : un service qui appelle une API d&rsquo;un partenaire externe qu&rsquo;on veut appeler uniquement en production, et donc mocker sur les environnements de d\u00e9veloppement et de test \/ UAT \/ staging. Quarkus essaye de d\u00e9porter au build time, via son plugin Maven ou Gradle, le plus de&#8230;<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/quarkus-tip-selectionner-un-bean-au-runtime\/\">Lire la suite<span class=\"screen-reader-text\"> Lire la suite<\/span><\/a><\/p><\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[9],"tags":[198,11,167,199],"class_list":["post-1326","post","type-post","status-publish","format-standard","hentry","category-informatique","tag-cdi","tag-java","tag-quarkus","tag-tips"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":1353,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/quarkus-tip-comment-ne-pas-creer-une-extension-quarkus\/","url_meta":{"origin":1326,"position":0},"title":"Quarkus Tip : Comment NE PAS cr\u00e9er une extension Quarkus","author":"admin","date":"mardi 16 novembre 2021","format":false,"excerpt":"Quand on d\u00e9veloppe une application compos\u00e9e de plusieurs composants, il est fr\u00e9quent de vouloir partager du code dans une librairie externe, par exemple via un JAR externe int\u00e9gr\u00e9 comme une d\u00e9pendance de vos composants. Quarkus est un framework d'extension, chaque extension qu'il propose permet d'int\u00e9grer une technologie (client BDD, framework\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1345,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/quarkus-et-les-google-cloud-functions\/","url_meta":{"origin":1326,"position":1},"title":"Quarkus et les  Google Cloud Functions","author":"admin","date":"mardi  2 novembre 2021","format":false,"excerpt":"Quarkus est un framework de d\u00e9veloppement de microservice pens\u00e9 pour le cloud et les conteneurs. Il est pens\u00e9 pour avoir une utilisation m\u00e9moire r\u00e9duite et un temps de d\u00e9marrage le plus court possible. Il se base principalement sur des standards (Jakarta EE, Eclipse MicroProfile, \u2026) et permet l'utilisation de librairies\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1440,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/google-cloud-functions-2nd-gen\/","url_meta":{"origin":1326,"position":2},"title":"Google Cloud Functions 2nd gen","author":"admin","date":"mardi 29 mars 2022","format":false,"excerpt":"Google vient de sortir en beta la seconde g\u00e9n\u00e9ration des Google Cloud Functions. Pour ceux qui ne connaissent pas encore les Google Cloud Functions vous pouvez lire mes articles J\u2019ai test\u00e9 Java Google Cloud Functions et Quarkus et les Google Cloud Functions. Cette seconde g\u00e9n\u00e9ration apporte : Un temps de\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/cloud-function-gen2-instances.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/cloud-function-gen2-instances.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/cloud-function-gen2-instances.png?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":923,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/devoxx-france-2019\/","url_meta":{"origin":1326,"position":3},"title":"Devoxx France 2019","author":"admin","date":"lundi 13 mai 2019","format":false,"excerpt":"Cette ann\u00e9e, j'ai eu la chance d'assister \u00e0 Devoxx France, j'ai m\u00eame eu la chance d'\u00eatre speaker et de donner deux talks (Mes premiers pas en deeplearning avec Keras et Arthas - Alibaba Java Diagnostic Tool ), mais \u00e7a je vous en parlerais plus tard ;) Voici un petit compte\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1138,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/ma-deuxieme-annee-chez-zenika\/","url_meta":{"origin":1326,"position":4},"title":"Ma deuxi\u00e8me ann\u00e9e chez Zenika","author":"admin","date":"jeudi  3 septembre 2020","format":false,"excerpt":"Aujourd\u2019hui est un jour sp\u00e9cial, cela fait deux ans que je suis arriv\u00e9 chez Zenika, apr\u00e8s 9 ans en tant qu\u2019architecte logiciel dans la DSI d\u2019un grand groupe de retail. L'ann\u00e9e derni\u00e8re j'avais fait le bilan de ma premi\u00e8re ann\u00e9e pass\u00e9e : 1 an chez Zenika. Et un an apr\u00e8s,\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1560,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/quarkus-tip-tester-une-fonction-google-cloud\/","url_meta":{"origin":1326,"position":5},"title":"Quarkus Tip : Tester une fonction Google Cloud","author":"admin","date":"jeudi 29 d\u00e9cembre 2022","format":false,"excerpt":"J'ai r\u00e9cemment contribu\u00e9 une PR \u00e0 Quarkus qui contient un framework de test pour les fonctions Google Cloud. Quarkus supporte la cr\u00e9ation de fonction Google Cloud de trois mani\u00e8res diff\u00e9rentes : En utilisant l'API de Google Cloud. En utilisant une extension HTTP de Quarkus : RESTEasy, Reactive routes, Servlet, Spring\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/posts\/1326","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/comments?post=1326"}],"version-history":[{"count":1,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/posts\/1326\/revisions"}],"predecessor-version":[{"id":1616,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/posts\/1326\/revisions\/1616"}],"wp:attachment":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/media?parent=1326"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/categories?post=1326"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/tags?post=1326"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}