Multi-module Multi-feature gradle project
Tags: springboot, gradle
Published: 2020-06-07 06:56:55

---
title: Multi-module Multi-feature gradle project
description: Resource server get custom user info
published: true
tags: ["springboot", "gradle"]
---

### Introduction

So you are starting new backend work and have planned to use spring boot because of existing java development skills in the team.
For me when i'll be in this situation i'll be like

Why would I choose spring boot?

* A LOT of boilerplate code is removed
* Have strong Spring framework support
* Good Support of DB layer more here(https://thorben-janssen.com/what-is-spring-data-jpa-and-why-should-you-use-it/)
* Handy and configurable Spring security
* Easier management of profiles
* Ready to use `starter-packs`
* And not to forget spring integration
* And many more plug and play components

If you have ever developed a servlet/jsp based application then you will find there is no `web.xml` in SpringBoot application.

While starting a new project it is very easy to jump start coding. As a normal spring boot application it is easy to get up and running from https://start.spring.io/ project and evolves as we develop further.

* Controllers
* Services
* Repositories


Until the features goes on increasing and the basic root package becomes collection of many sub packages and then you need drill down or search for matching file of a feature.

```yaml
in.silentsudo
    configs
        mysql
        kafka
    controllers
        validators
            annotations
                [@interface]
        dto
            [*.java]
        [either-feature-wise packaging or individuals]
    services
        [either-feature-wise packaging or individuals]
    reposotories
        domain
            [*.java]
        dto
            [*.java]
        [either-feature-wise packaging or individuals]

```

Spring project by default is shipped with either maven or gradle build tool. We use this to further structure our code properly.
Instead of getting right into developing a feature we can spend some time deciding meta info about the feature.
Consider a simple use case of file uploading feature. If we are ok to share our credentials to the public client then the burden on this feature reduces. But since this is our sample usecase we are not sharing any credentials to the public client to have write access to our storage system and it is through the api server itself a user can upload a file. :rage:

Let's try to define our interface before we start anything else.
Simple File Upload feature-
* Get a file 
* store in one of the provider we are supporting[disk, aws or azure storage]


### Implementation

Definition is as below:

![png](https://dev-to-uploads.s3.amazonaws.com/i/ehc8k565983i5wsl1cgb.png)

Create the following project structure:

```sh
PROJECT_ROOT
    build.gradle
    settings.gradle
```

This becomes the root of the project.
All child project mentioned below reside under PROJECT_ROOT.

* Spring boot web application
* storageservice(base interface for storing files)
* awsstoreservice(concrete implementation of storageservice to fulfill storing file on aws)
* azurestoreservice(concrete implementation of storageservice to fulfill storing file on aws)
* diskstorageservuce(concrete implementation of storageservice to fulfill storing file on local or attached disk)


Create a base interface definition project module inside `PROJECT_ROOT`.

This is how it should look.

```sh
PROJECT_ROOT
    build.gradle
    settings.gradle
    storageservice
        build
        src
        build.gradle
```

The only code in this module is this

```java
package in.silentsudo.storageservice;

import java.io.File;

public interface FileStorageService {
    String store(File file);
}

```

Similarly lets create different implementers for this 
```sh
PROJECT_ROOT
    build.gradle
    settings.gradle
    storageservice
        build
        src
        build.gradle
    diskstorageservice
        build
        src
        build.gradle
    awsstorageservice
        build
        src
        build.gradle
    azurestorageservice
        build
        src
        build.gradle                       
```

One of the sample implementer like this

For example, if AwsStore is implemented as below:

```java
@Service
@Qualifier("awsstore")
public class AwsStore implements FileStorageService {
    // Define bunch of constant or a connection/reference to aws store to put file
    @Override
    public String store(File file) {
        // awsSdk.store(file) similar call
        return "Storing File in AWS Storage";
    }
}
```
Finally create application module which uses these services

```sh
PROJECT_ROOT
    build.gradle
    settings.gradle
    storageservice
        build
        src
        build.gradle
    diskstorageservice
        build
        src
        build.gradle
    awsstorageservice
        build
        src
        build.gradle
    azurestorageservice
        build
        src
        build.gradle                       
    application
        build
        src
        build.gradle         
```

At this moment we have not configured any of the dependencies for any module.

As shown in above diagram diskstorageservice, awsstorageservice, azurestorageservice are concrete implementer of storageservice which just defines the contract to store. Here implementers by their name indicates where they are storing those files.

Directory structure for this.


![png](https://dev-to-uploads.s3.amazonaws.com/i/wxz76vrelu75s12qqfql.png)

dependencies of application module is as follow:

```gradle
implementation project(':storageservice')
implementation project(':diskstorageservice')
implementation project(':awsstore')
```


### Usage
Let us see how we can use this different implementation of storage service

```java
@SpringBootApplication(scanBasePackages = "in.silentsudo")
@RestController
public class MainApplication {

    private final MyService myService;
    private final FileStorageService fileStorageService;
    private final FileStorageService awsStore;

    @Autowired
    public MainApplication(MyService myService,
                           @Qualifier("diskstorage") FileStorageService diskStorageService,
                           @Qualifier("awsstore") FileStorageService awsStore) {
        this.myService = myService;
        this.fileStorageService = diskStorageService;
        this.awsStore = awsStore;
    }

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

    // This is post request all the time, get is for demo purpose
    @GetMapping("/store")
    public String store() {
        // You would get file from request this is for test purpose
        return fileStorageService.store(new File("/home/ashish/remove_outliers"));
    }

    // This is post request all the time, get is for demo purpose
    @GetMapping("/awsstore")
    public String awsStore() {
        // You would get file from request this is for test purpose
        return awsStore.store(new File("/home/ashish/remove_outliers"));
    }
}
```

Note `@Qualifier` annotation is used to locate bean with name specified because in our use case if you can see 
```java
 @Autowired
    public MainApplication(MyService myService,
                           @Qualifier("diskstorage") FileStorageService diskStorageService,
                           @Qualifier("awsstore") FileStorageService awsStore) {
        this.myService = myService;
        this.fileStorageService = diskStorageService;
        this.awsStore = awsStore;
    }
```
We are trying to wire aws/azure/disk store for reference to FileStorageService. It is as good as asking 
```
Give me concrete implementer of `FileStorageService` named `awsstore`
```

Of Course no one uses different storage mechanism but this same principle can be used for example when implementing 
mongodb and mysql in the same project for different use cases.
This implementation gives feature separation in large projects where dependencies are not cluttered in 1 build.gradle file instead they are in their own modules. Modules are not limited to spring-boot modules only but can be any library module.
If It is modular to write, it should be modular enough to separate it in a module.

### Source Code 
https://gitlab.com/silentsudo/spring-boot-multi-module-project


### Reference
https://spring.io/guides/gs/multi-module/

### Article source
https://silentsudo.gitlab.io/post/spring-boot/2020-05-05-multimodule-gradle-project-with-interface-fitst-design-approach/