Kontexthierarchie mit der Spring Boot Fluent Builder-API

Kontexthierarchie mit der Spring Boot Fluent Builder-API

1. Überblick

In Spring Boot können separate Kontexte erstellt und in einer Hierarchie organisiert werden.

Eine Kontexthierarchie kann in der Spring Boot-Anwendung auf verschiedene Arten definiert werden. In diesem Artikel sehen wir unshow we can create multiple contexts using the fluent builder API an.

Da wir nicht näher auf das Einrichten einer Spring Boot-Anwendung eingehen, sollten Sie sich diesearticle ansehen.

2. Anwendungskontexthierarchie

Wir können mehrere Anwendungskontexte haben, die eine Eltern-Kind-Beziehung teilen.

A context hierarchy allows multiple child contexts to share beans which reside in the parent context. Jeder untergeordnete Kontext kann die vom übergeordneten Kontext geerbte Konfiguration überschreiben.

Außerdem können wir Kontexte verwenden, um zu verhindern, dass in einem Kontext registrierte Beans in einem anderen zugänglich sind. Dies erleichtert die Erzeugung von lose gekoppelten Modulen.

Hier sind einige Punkte erwähnenswert, dass ein Kontext nur ein Elternteil haben kann, während ein Elternkontext mehrere Kindkontexte haben kann. Ein untergeordneter Kontext kann auch auf Beans im übergeordneten Kontext zugreifen, nicht jedoch umgekehrt.

3. Verwenden derSpringApplicationBuilder API

Die KlasseSpringApplicationBuilder bietet eine fließende API zum Erstellen einer Eltern-Kind-Beziehung zwischen Kontexten mithilfe der Methodenparent(),child() andsibling().

Zur Veranschaulichung der Kontexthierarchiewe’ll set up a non-web parent application context with 2 child web contexts.

Um dies zu demonstrieren, starten wir zwei Instanzen von eingebettetem Tomcat, die jeweils einen eigenen Webanwendungskontext haben und beide in einer einzigen JVM ausgeführt werden.

3.1. Übergeordneter Kontext

Erstellen Sie zunächst eine Service-Bean zusammen mit einer Bean-Definitionsklasse, die sich im übergeordneten Paket befindet. Wir möchten, dass diese Bean eine Begrüßung zurückgibt, die dem Client unserer Webanwendung angezeigt wird:

@Service
public class HomeService implements IHomeService {

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

Und die Bean-Definitionsklasse:

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

Als Nächstes erstellen wir die Konfiguration für die beiden untergeordneten Kontexte.

3.2. Untergeordneter Kontext

Da alle Kontexte mithilfe der Standardkonfigurationsdatei konfiguriert werden, müssen separate Konfigurationen für Eigenschaften bereitgestellt werden, die nicht für Kontexte wie Serverports freigegeben werden können.

Um zu verhindern, dass widersprüchliche Konfigurationen von der automatischen Konfiguration erfasst werden, werden die Klassen auch in separaten Paketen gespeichert.

Beginnen wir mit der Definition einer Eigenschaftendatei für den ersten untergeordneten Kontext:

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

Beachten Sie, dass wir den Port- und Kontextpfad sowie einen JMX-Namen konfiguriert haben, damit die Anwendungsnamen nicht in Konflikt geraten.

Fügen wir nun die Hauptkonfigurationsklasse für diesen Kontext hinzu:

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

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

Diese Klasse bietet eine neue Definition für die BeanhomeService, die die vom übergeordneten Bean überschreibt.

Sehen wir uns die Definition derGreetingService-Klasse an:

@Service
public class GreetingService implements IHomeService {

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

Schließlich fügen wir einen Controller für diesen Webkontext hinzu, der diehomeService-Bean verwendet, um dem Benutzer eine Nachricht anzuzeigen:

@Controller
public class Ctx1Controller {

    @Autowired
    HomeService homeService;

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

        return homeService.getGreeting();
    }
}

3.3. Geschwisterkontext

Für unseren zweiten Kontext erstellen wir eine Controller- und Konfigurationsklasse, die den im vorherigen Abschnitt sehr ähnlich sind.

Dieses Mal erstellen wir keinehomeService-Bean, da wir über den übergeordneten Kontext darauf zugreifen.

Fügen wir zunächst eine Eigenschaftendatei für diesen Kontext hinzu:

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

Und die Konfigurationsklasse für die Geschwisteranwendung:

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

Fügen wir auch einen Controller hinzu, derHomeService als Abhängigkeit hat:

@RestController
public class Ctx2Controller {

    @Autowired
    IHomeService homeService;

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

In diesem Fall sollte unser Controller die BeanhomeServiceaus dem übergeordneten Kontext abrufen.

3.4. Kontexthierarchie

Jetzt können wir alles zusammenfügen und die Kontexthierarchie mitSpringApplicationBuilder: definieren

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);
    }
}

Schließlich können wir beim Ausführen der Spring Boot App mitlocalhost:8081/ctx1/home andlocalhost:8082/ctx2/greeting. auf beide Anwendungen an ihren jeweiligen Ports zugreifen

4. Fazit

Mit der APISpringApplicationBuilderhaben wir zunächst eine Eltern-Kind-Beziehung zwischen zwei Kontexten einer Anwendung erstellt. Als Nächstes wurde erläutert, wie die übergeordnete Konfiguration im untergeordneten Kontext überschrieben wird. Zuletzt haben wir einen Geschwisterkontext hinzugefügt, um zu demonstrieren, wie die Konfiguration im übergeordneten Kontext mit anderen untergeordneten Kontexten geteilt werden kann.

Der Quellcode des Beispiels istover on GitHub verfügbar.