Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

It’s possible to create separate contexts and organize them in a hierarchy in Spring Boot.

A context hierarchy can be defined in different ways in Spring Boot application. In this article, we’ll look at how we can create multiple contexts using the fluent builder API.

As we won’t go into details on how to set up a Spring Boot application, you might want to check out this article.

2. Application Context Hierarchy

We can have multiple application contexts that share a parent-child relationship.

A context hierarchy allows multiple child contexts to share beans which reside in the parent context. Each child context can override configuration inherited from the parent context.

Furthermore, we can use contexts to prevent beans registered in one context from being accessible in another. This facilitates the creation of loosely coupled modules.

Here some points worth noting are that a context can have only one parent while a parent context can have multiple child contexts. Also, a child context can access beans in the parent context but not vice-versa.

3. Using SpringApplicationBuilder API

The SpringApplicationBuilder class provides a fluent API to create a parent-child relationship between contexts using parent(), child() and sibling() methods.

To exemplify the context hierarchy, we’ll set up a non-web parent application context with 2 child web contexts.

To demonstrate this, we’ll start two instances of embedded Tomcat each with its own web application context and both running in a single JVM.

3.1. Parent Context

To begin, let’s create a service bean along with a bean definition class which reside in the parent package. We want this bean to return a greeting which is displayed to the client of our web application:

@Service
public class HomeService implements IHomeService {

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

And the bean definition class:

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

Next, we’ll create the configuration for the two child contexts.

3.2. Child Context

Since all contexts are configured using the default configuration file, we need to provide separate configurations for properties which cannot be shared among contexts such as server ports.

To prevent conflicting configurations being picked up by the auto-configuration, we’ll also keep the classes in separate packages.

Let’s start by defining a properties file for the first child context:

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

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

Note that we’ve configured the port and context path, as well as a JMX name so the application names don’t conflict.

Let’s now add the main configuration class for this context:

@Configuration
@ComponentScan("com.baeldung.ctx1")
@EnableAutoConfiguration
public class Ctx1Config {
    
    @Bean
    public IHomeService homeService() {
        return new GreetingService();
    }
}

This class provides a new definition for the homeService bean that will overwrite the one from the parent.

Let’s see the definition of the GreetingService class:

@Service
public class GreetingService implements IHomeService {

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

Finally, we’ll add a controller for this web context that use the homeService bean to display a message to the user:

@RestController
public class Ctx1Controller {

    @Autowired
    private HomeService homeService;

    @GetMapping("/home")
    public String greeting() {
        return homeService.getGreeting();
    }
}

3.3. Sibling Context

For our second context, we’ll create a controller and configuration class which are very similar to the ones in the previous section.

This time, we won’t create a homeService bean – as we’ll access it from the parent context.

First, let’s add a properties file for this context:

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

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

And the configuration class for the sibling application:

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

Let’s also add a controller, which has HomeService as a dependency:

@RestController
public class Ctx2Controller {

    @Autowired
    private IHomeService homeService;

    @GetMapping("/greeting")
    public String getGreeting() {
        return homeService.getGreeting();
    }
}

In this case, our controller should get the homeService bean from the parent context.

3.4. Context Hierarchy

Now we can put everything together and define the context hierarchy using SpringApplicationBuilder:

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

Finally, on running the Spring Boot App we can access both applications at their respective ports using localhost:8074/ctx1/home and localhost:8075/ctx2/greeting.

4. Conclusion

Using the SpringApplicationBuilder API, we first created a parent-child relationship between two contexts of an application. Next, we covered how to override the parent configuration in the child context. Lastly, we added a sibling context to demonstrate how the configuration in the parent context can be shared with other child contexts.

The source code of the example is available over on GitHub.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.