Hiérarchie de contexte avec l’API Spring Boot Fluent Builder

Hiérarchie de contexte avec l'API Spring Boot Fluent Builder

1. Vue d'ensemble

Il est possible de créer des contextes séparés et de les organiser dans une hiérarchie dans Spring Boot.

Une hiérarchie de contexte peut être définie de différentes manières dans l'application Spring Boot. Dans cet article, nous examineronshow we can create multiple contexts using the fluent builder API.

Comme nous n'entrerons pas dans les détails sur la façon de configurer une application Spring Boot, vous voudrez peut-être consulter cearticle.

2. Hiérarchie du contexte d'application

Nous pouvons avoir plusieurs contextes d'application qui partagent une relation parent-enfant.

A context hierarchy allows multiple child contexts to share beans which reside in the parent context. Chaque contexte enfant peut remplacer la configuration héritée du contexte parent.

De plus, nous pouvons utiliser des contextes pour empêcher les beans enregistrés dans un contexte d'être accessibles dans un autre. Cela facilite la création de modules faiblement couplés.

Il convient de noter ici qu’un contexte ne peut avoir qu’un seul parent alors qu’un contexte parent peut avoir plusieurs contextes enfants. De plus, un contexte enfant peut accéder aux beans dans le contexte parent mais pas l'inverse.

3. Utilisation de l'APISpringApplicationBuilder

La classeSpringApplicationBuilder fournit une API fluide pour créer une relation parent-enfant entre les contextes à l'aide des méthodesparent(),child() andsibling().

Pour illustrer la hiérarchie du contexte,we’ll set up a non-web parent application context with 2 child web contexts.

Pour illustrer cela, nous allons démarrer deux instances de Tomcat intégré, chacune avec son propre contexte d'application Web et toutes deux exécutées dans une seule JVM.

3.1. Contexte parent

Pour commencer, créons un bean de service avec une classe de définition de bean qui résident dans le package parent. Nous voulons que ce haricot renvoie un message d'accueil qui est affiché au client de notre application Web:

@Service
public class HomeService implements IHomeService {

    public String getGreeting() {
        return "Welcome User";
    }
}

Et la classe de définition de haricot:

@Configuration
@ComponentScan("com.example.parent")
public class ServiceConfig {}

Ensuite, nous allons créer la configuration pour les deux contextes enfants.

3.2. Contexte enfant

Étant donné que tous les contextes sont configurés à l'aide du fichier de configuration par défaut, nous devons fournir des configurations distinctes pour les propriétés qui ne peuvent pas être partagées entre des contextes tels que les ports de serveur.

Pour éviter que des configurations conflictuelles ne soient détectées par la configuration automatique, nous conserverons également les classes dans des packages séparés.

Commençons par définir un fichier de propriétés pour le premier contexte enfant:

server.port=8081
server.servlet.context-path=/ctx1

spring.application.admin.enabled=false
spring.application.admin.jmx-name=org.springframework.boot:type=Ctx1Rest,name=Ctx1Application

Notez que nous avons configuré le port et le chemin de contexte, ainsi qu'un nom JMX afin que les noms d'application ne soient pas en conflit.

Ajoutons maintenant la classe de configuration principale pour ce contexte:

@Configuration
@ComponentScan("com.example.ctx1")
@EnableAutoConfiguration
public class Ctx1Config {

    @Bean
    public IHomeService homeService() {
        return new GreetingService();
    }
}

Cette classe fournit une nouvelle définition pour le beanhomeService qui écrasera celle du parent.

Voyons la définition de la classeGreetingService:

@Service
public class GreetingService implements IHomeService {

    public String getGreeting() {
        return "Greetings for the day";
    }
}

Enfin, nous allons ajouter un contrôleur pour ce contexte Web qui utilise le beanhomeService pour afficher un message à l'utilisateur:

@Controller
public class Ctx1Controller {

    @Autowired
    HomeService homeService;

    @GetMapping("/home")
    @ResponseBody
    public String greeting() {

        return homeService.getGreeting();
    }
}

3.3. Contexte de la fratrie

Pour notre deuxième contexte, nous allons créer un contrôleur et une classe de configuration qui sont très similaires à ceux de la section précédente.

Cette fois, nous ne créerons pas de beanhomeService, car nous y accèderons à partir du contexte parent.

Tout d'abord, ajoutons un fichier de propriétés pour ce contexte:

server.port=8082
server.servlet.context-path=/ctx2

spring.application.admin.enabled=false
spring.application.admin.jmx-name=org.springframework.boot:type=WebAdmin,name=SpringWebApplication

Et la classe de configuration pour l'application jumelle:

@Configuration
@ComponentScan("com.example.ctx2")
@EnableAutoConfiguration
@PropertySource("classpath:ctx2.properties")
public class Ctx2Config {}

Ajoutons également un contrôleur, qui aHomeService comme dépendance:

@RestController
public class Ctx2Controller {

    @Autowired
    IHomeService homeService;

    @GetMapping(value = "/greeting", produces = "application/json")
    public String getGreeting() {
        return homeService.getGreeting();
    }
}

Dans ce cas, notre contrôleur devrait récupérer le beanhomeService du contexte parent.

3.4. Hiérarchie de contexte

Nous pouvons maintenant tout rassembler et définir la hiérarchie du contexte en utilisantSpringApplicationBuilder:

public class App {
    public static void main(String[] args) {
        new SpringApplicationBuilder()
          .parent(ParentConfig.class).web(WebApplicationType.NONE)
          .child(WebConfig.class).web(WebApplicationType.SERVLET)
          .sibling(RestConfig.class).web(WebApplicationType.SERVLET)
          .run(args);
    }
}

Enfin, en exécutant l'application Spring Boot, nous pouvons accéder aux deux applications sur leurs ports respectifs en utilisantlocalhost:8081/ctx1/home andlocalhost:8082/ctx2/greeting.

4. Conclusion

À l'aide de l'APISpringApplicationBuilder, nous avons d'abord créé une relation parent-enfant entre deux contextes d'une application. Nous avons ensuite expliqué comment remplacer la configuration parent dans le contexte enfant. Enfin, nous avons ajouté un contexte frère afin de montrer comment la configuration dans le contexte parent peut être partagée avec d'autres contextes enfants.

Le code source de l'exemple est disponibleover on GitHub.