Is there a way to know if there are more than one Spring Context in use?

Viewed 401

I have 2 spring boot applications - an API service and a library.

library generates a non-executable, imporatable JAR, which is imported and used by API service. Here is the pom:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>

        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>library</artifactId>
    <version>0.0.1</version>
    <packaging>jar</packaging>
    <name>library</name>
    <description>Library Integration</description>

    <properties>
        <java.version>11</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <oauth2.version>2.1.1.RELEASE</oauth2.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
            <version>${oauth2.version}</version>
        </dependency>
    </dependencies>
</project>

Some other info about library project:

  1. It does not have a class with main method i.e., no @SpringBootApplication

  2. It has a Configuration class that scans components:

    @Configuration

    @ComponentScan("com.example.library")

    public class LibraryConfiguration {}

  3. In /resources/META-INF/spring.factories we read this configuration:

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
    com.example.library.LibraryConfiguration

This had to be done, as when we are importing library in API service project, API service is not able to find the classes which we want to use there. These classes are beans and hence need to be initialized.

For API service project, pom is like this:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>api-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>api service</name>
    <description>api service</description>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- JUnit -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <dependency>
        <groupId>com.example</groupId>
        <artifactId>library</artifactId>
        <version>0.0.1</version>
    </dependency>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

APIs of API service project use methods of library project. The project works fine, all the APIs work.

However, I would like to confirm that only one Spring context is in use and not 2. When API service is started, it has its own context. Then it gets library dependency, which might create its own context and initialise beans of library project.

Ideally, I would like that there is only one context and that is of API service project. Is there a way to ensure this?

3 Answers

library does not create the context. However you can check it by Autowiring the ApplicationContext in your main boot class and printing the ID and display name for example :-

@Autowired private ApplicationContext applicationContext;

System.out.println(applicationContext.getDisplayName());
System.out.println(applicationContext.getId());

There will not be two application context for your case since you don't have SpringBoot main class in library. In springboot application context is created when SpringApplication.run(this,args) is called.

I have created a similar Spring Boot Project few days back. This question didn't cross my mind ever. Reason being, How context get created and there can't be two Contexts.

  1. You start your application by providing a main Class ( You can't provide two).
  2. Application Context / BeanFactory are Spring managed Bean, Your Library is not different from any Spring boot dependency ( Spring MVC, Spring Security). In a single Application instance it will not create two different Contexts.

In Order to Verify. Write Below code in any Spring Managed Bean. If Spring boot comes up and doesn't give any Exception e.g. Multiple Beans of type ApplicationContext found. That will be a proof.

@Autowired
private ApplicationContext applicationContext;

Alternatively, Include a Actuator dependency and hit below URL . It will give you all beans created. Context is just a bean, Check if there are multiple Beans.

http://<address>:<management-port>/beans. 
Related