Spring Boot multi module development, bean calling of sub modules and Solutions

Posted by Tchelo on Sat, 23 Oct 2021 17:13:42 +0200

Spring Boot multi module project

1. Create a maven project

Project Name: spring boot sample project

Delete the redundant files and leave only the pom.xml file in the spring boot sample project project

2. Add sub modules in spring boot sample project project

New: spring boot sample API module. Pay attention to the package name com.example.sample.api at position 2 in the figure, because mutual calls between multiple modules will be involved later. In order to facilitate scanning, unify the package name into the name of com.example.sample. Module

Similarly, add the spring boot sample web module. Select the dependencies required for Spring Boot web development. Here, I checked Spring Web and Lombok

Finally, the whole project directory is as follows:

3. Configure pom.xml file

3.1 pom.xml of the parent project spring boot sample project

1. The first is the basic information of the parent project

<!-- essential information -->
    <description>Spring Boot Multi module construction</description>
    <modelVersion>4.0.0</modelVersion>
    <name>spring-boot-sample</name>
    <packaging>pom</packaging>

    <!-- Project Description: This is the parent project of the aggregation project -->
    <groupId>com.example</groupId>
    <artifactId>spring-boot-sample-project</artifactId>
    <version>1.0-SNAPSHOT</version>

2. Because the whole project will depend on Spring Boot, Spring Boot sample project needs to inherit the Spring Boot parent class

<!-- Inheritance Description: inherit here SpringBoot Parent project provided -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

3. Declare sub modules and put the created sub modules into modules

<!-- Module description: multiple sub modules are declared here -->
    <modules>
        <module>spring-boot-sample-api</module>
        <module>spring-boot-sample-web</module>
    </modules>

4. For version management, you can put dependencies such as sub modules that need version management into dependency management for version management

 <!-- Version Description: the dependent version numbers are uniformly managed here -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.example</groupId>
                <artifactId>spring-boot-sample-api</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
            <dependency>
                <groupId>com.example</groupId>
                <artifactId>spring-boot-sample-web</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

5. Other

3.1.1. Complete pom.xml configuration code of parent project
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <!-- essential information -->
    <description>Spring Boot Multi module construction</description>
    <modelVersion>4.0.0</modelVersion>
    <name>spring-boot-sample-project</name>
    <packaging>pom</packaging>

    <!-- Project Description: This is the parent project of the aggregation project -->
    <groupId>com.example</groupId>
    <artifactId>spring-boot-sample-project</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- Inheritance Description: inherit here SpringBoot Parent project provided -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <!-- Module description: multiple sub modules are declared here -->
    <modules>
        <module>spring-boot-sample-api</module>
        <module>spring-boot-sample-web</module>
    </modules>
    <!--jdk edition -->
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <!-- Version Description: the dependent version numbers are uniformly managed here -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.example</groupId>
                <artifactId>spring-boot-sample-api</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
            <dependency>
                <groupId>com.example</groupId>
                <artifactId>spring-boot-sample-web</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
        </dependencies>
    </dependencyManagement>


</project>

3.2. Configure sub module pom.xml

The configuration of sub modules is similar, so take the configuration of spring boot sample WEBweb as an example

1. Comment out the default Spring Boot parent project of the sub module,

Configure the parent project of the sub module to inherit from the spring boot sample project

 <!--<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> &lt;!&ndash; lookup parent from repository &ndash;&gt;
    </parent>-->
    <!--Modify inherited parent project-->
    <parent>
        <groupId>com.example</groupId>
        <artifactId>spring-boot-sample-project</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

2. The dependency of the sub module itself, because the web module will depend on the api module, so the spring boot sample api dependency is added

<dependencies>
    <!--rely on spring-boot-sample-api -->
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>spring-boot-sample-api</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
3.2.1 complete pom.xml configuration of sub module
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         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.5.6</version>
        <relativePath/> &lt;!&ndash; lookup parent from repository &ndash;&gt;
    </parent>-->
    <!--Modify inherited parent class-->
    <parent>
        <groupId>com.example</groupId>
        <artifactId>spring-boot-sample-project</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.example</groupId>
    <artifactId>spring-boot-sample-web</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-boot-sample-web</name>
    <description>Demo project for Spring Boot</description>

    <dependencies>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>spring-boot-sample-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

3.3 others

Of course, the dependency of the web module can also be directly placed in the pom.xml of the parent project, so that it can be used as long as it inherits the POM of the parent project. For example, if spring boot starter web is placed in the POM dependency of the parent project, the sub module will not have to depend again as long as it inherits the parent project.

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

4. Start

4.1. Start the spring boot sample project project

Generally, only one startup class is left in the whole project, so we delete the startup class in the api and only the startup class of the sub module spring boot sample web. If we find the startup class, we can run it directly

Direct access after successful startup: http://localhost:8080/ , the following page shows that we succeeded.

4.2. Solve the problem of multi module call

4.2.1 sub module spring boot starter web test code.

We add simple test code to the web module. The code is as follows

package com.example.sample.web.controller;

import com.example.sample.web.service.IHelloService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * HelloController class
 *
 * @author zhangl
 * @date 2021/10/23 13:42
 */
@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello(){
        return "Hello World ! ";
    }
}

Operation results:

Add a service interface call. The HelloController code is as follows:

package com.example.sample.web.controller;

import com.example.sample.web.service.IHelloService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * HelloController class
 *
 * @author zhangl
 * @date 2021/10/23 13:42
 */
@RestController
public class HelloController {
    @Resource
    private IHelloService helloService;
    @GetMapping("/hello")
    public String hello(){
        return "Hello World ! " + helloService.sayHello();
    }
}

The interface IHelloService code is as follows:

package com.example.sample.web.service;

import org.springframework.stereotype.Service;

/**
 * iHelloService interface
 *
 * @author zhangl
 * @date 2021/10/23 13:43
 */
@Service
public interface IHelloService {
    /**
     * test method
     * @return
     */
    String sayHello();
}

The code of the implementation class HelloServiceImpl is as follows

package com.example.sample.web.service.impl;

import com.example.sample.web.service.IHelloService;
import org.springframework.stereotype.Service;

/**
 * HelloServiceImpl class
 *
 * @author zhangl
 * @date 2021/10/23 13:44
 */
@Service(value = "iHelloService")
public class HelloServiceImpl implements IHelloService {
    @Override
    public String sayHello() {
        return "Hello IHelloServiceImpl ... ";
    }
}

The code structure is as follows:

As a result, the string in the called method sayHello is spliced behind Hello World

4.2.2 the Web module uses the code of the spring boot sample API module

In the spring boot sample API module, create a class itetapiservice, which has a * * success() * * method to return a string

package com.example.sample.api.service;

import org.springframework.stereotype.Service;

/**
 * TestApiService interface
 *
 * @author zhangl
 * @date 2021/10/23 14:03
 */
@Service
public interface ITestApiService {
    /**
     * Returns a string
     * @return
     */
    String success();
}

Implement the class TestApiServiceImpl and return the string * * "seeing this string indicates that your multi module call is successful!"**

package com.example.sample.api.service.impl;

import com.example.sample.api.service.ITestApiService;
import org.springframework.stereotype.Service;

/**
 * TestApiServiceImpl class
 *
 * @author zhangl
 * @date 2021/10/23 14:04
 */
@Service(value = "iTestApiService")
public class TestApiServiceImpl implements ITestApiService {
    @Override
    public String success() {
        return " Seeing this string indicates that your multi module call is successful!";
    }
}

Inject the itetapiservice class into the HelloController of spring boot starter web. The code is as follows

package com.example.sample.web.controller;

import com.example.sample.api.service.ITestApiService;
import com.example.sample.web.service.IHelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * HelloController class
 *
 * @author zhangl
 * @date 2021/10/23 13:42
 */
@RestController
public class HelloController {
    @Resource
    private IHelloService helloService;
    /**
     *  Itetapiservice interface of injection api module
      */
    @Resource
    private ITestApiService testApiService;
    @GetMapping("/hello")
    public String hello(){
        //Splice character
        return "Hello World ! " + helloService.sayHello() + testApiService.success();
    }
}

The project structure is as follows:

Operation, error reporting

***************************
APPLICATION FAILED TO START
***************************

Description:

A component required a bean of type 'com.example.sample.api.service.ITestApiService' that could not be found.


Action:

Consider defining a bean of type 'com.example.sample.api.service.ITestApiService' in your configuration.

Solution: add an annotation in the startup class and specify the scanned package@ ComponentScan(basePackages = {"com.example.sample"}), the code is as follows:

package com.example.sample.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

/**
 *
 * @author zhangl
 */
@ComponentScan(basePackages = {"com.example.sample"})//Scan the files under com.example.sample
@SpringBootApplication
public class SpringBootSampleWebApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootSampleWebApplication.class, args);
    }

}

Of course, there are other ways to solve it. However, only the @ ComponentScan annotation is introduced here

Start again and access http://localhost:8080/hello , the results are as follows:

5. Sample code

Code hosted on https://gitee.com/zzhangleiz/spring-boot-sample.git

Topics: Java Spring Spring Boot