Spring Boot Best Practices



In this article, I would like to discuss a few Spring boot best practices that we can use in our Spring boot applications.

Following are list of Spring boot best practices that we will discuss:

1. Standard Project Structure for Spring Boot Projects
2. Using Java-based configuration - @Configuration
3. Using Auto-configuration
4. Use Spring Initializr for starting new Spring Boot projects
5. When to Use Constructor-based and setter-based DI in Spring or Spring boot applications
6. Using @Service Annotation Class for Business Layer
7. Spring Bean Naming Conventions
8. Handle Circular dependencies
9. Exception Handling in Spring boot Rest API projects
10. Follow Restful API Design Best Practices in Spring Boot Rest API Applications

1. Standard Project Structure for Spring Boot Projects

Here, I will show you recommended ways to create spring boot project structure in Spring boot applications, which will help beginners to maintain standard coding structure.

Don't use the “default” Package

When a class does not include a package declaration, it is considered to be in the “default package”. The use of the “default package” is generally discouraged and should be avoided. It can cause particular problems for Spring Boot applications that use the @ComponentScan@EntityScan, or @SpringBootApplication annotations since every class from every jar is read.
I recommend that you follow Java’s recommended package naming conventions and use a reversed domain name (for example, com.javaguides.projectname).
To know standard package naming conventions, check out - about Java Packages with Examples.
Here, I recommend two approaches to create a standard project structure in Spring boot applications.

Project Structure - First approach

The following spring boot project structure shows a typical layout recommended by spring boot team:

Project Structure - Second approach

However, the above typical layout approach works well but some of the developers prefer to use the following packaging or project structure: 
Separate package for each layer like a model, controller, dao and service etc.

2. Using Java-based configuration - @Configuration

Spring Boot favors Java-based configuration. Although it is possible to use SpringApplication with XML sources, I generally recommend that your primary source be a single @Configuration class. Usually, the class that defines the main method is a good candidate as the primary @Configuration or @SpringBootApplication annotation.
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
         SpringApplication.run(Application.class, args);
    }
}
It is always a good practice to divide a large Spring-based configuration file into multiple files as per your convenience. I generally keep Database configuration in one file (DatabaseConfig), Spring MVC beans in another file etc, and then finally import in the main file.

Below example demonstrate the same here.

Importing Additional Configuration Classes

You need not put all your @Configuration into a single class. The @Import annotation can be used to import additional configuration classes.
For example:
@Configuration
public class DataSourceConfig {
    @Bean
    public DataSource dataSource() {
        return new DriverManagerDataSource(...);
    }
}
Let's import above additional configuration into AppConfig class:
@Configuration
@AnnotationDrivenConfig
@Import(DataSourceConfig.class) // <-- AppConfig imports DataSourceConfig
public class AppConfig extends ConfigurationSupport {
    @Autowired DataSourceConfig dataSourceConfig;

    @Bean
    public void TransferService transferService() {
        return new TransferServiceImpl(dataSourceConfig.dataSource());
    }
}
Multiple configurations may be imported by supplying an array of classes to the @Import annotation:
@Configuration
@Import({ DataSourceConfig.class, TransactionConfig.class })
public class AppConfig extends ConfigurationSupport {
    // @Bean methods here can reference @Bean methods in DataSourceConfig or TransactionConfig
}

3. Using Auto-configuration

Spring Boot auto-configuration attempts to automatically configure your Spring application based on the jar dependencies that you have added. For example, if HSQLDB is on your classpath, and you have not manually configured any database connection beans, then Spring Boot auto-configures an in-memory database.
You need to opt-in to auto-configuration by adding the @EnableAutoConfiguration or @SpringBootApplication annotations to one of your @Configuration classes.
You should only ever add one @SpringBootApplication or @EnableAutoConfiguration annotation. Spring boot team generally recommend that you add one or the other to your primary @Configuration class only.

If you don't require all auto-configuration stuff then you gradually replace auto-configuration. Read more about auto-configuration at https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/using-spring-boot.html#using-boot-auto-configuration

4. Use Spring Initializr for starting new Spring Boot projects

There are many ways to create a Spring Boot application. The simplest way is to use Spring Initializr at http://start.spring.io/, which is an online Spring Boot application generator.

5. When to Use Constructor-based and setter-based DI in Spring or Spring boot applications

From spring Framework documentation, Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the @Required annotation on a setter method can be used to make the property a required dependency.
Which of these DI methods is better purely depends on your scenario and some requirements. The following best practices may provide a guideline:
  1. Use constructor-based DI for mandatory dependencies so that your bean is ready to use when it is first called. 
  2. When your constructor gets stuffed with a large number of arguments, it's the figurative bad code smell. It's time to break your bean into smaller units for maintainability. 
  3. Use setter-based DI only for optional dependencies or if you need to reinject dependencies later, perhaps using JMX. 
  4. Avoid circular dependencies that occur when a dependency (say, bean B) of your bean (bean A) directly or indirectly depends on the same bean again (bean A), and all beans involved use constructor-based DI. You may use setter-based DI here. 
  5. You can mix constructor-based and setter-based DI for the same bean, considering mandatory, optional, and circular dependencies. 

6. Using @Service Annotation Class for Business Layer

I observed in many of the spring boot open source application, the Spring Data JPA repositories directly called in Controller classes in Spring boot applications. I generally use Service class annotated with a @Service annotation to write business-related logic so you can follow this approach.
For example, UserService, CustomerService, EmployeeService etc.

I listed a few free spring boot projects here at 10+ Free Open Source Projects Using Spring Boot article.

7. Spring Bean Naming Conventions

The convention is to use the standard Java convention for instance field names when naming beans. That is, bean names start with a lowercase letter, and are camel-cased from then on.
Examples of such names would be (without quotes) 'accountManager', 'accountService', 'userDao', 'loginController', and so forth.
Naming beans consistently make your configuration easier to read and understand, and if you are using Spring AOP it helps a lot when applying advice to a set of beans related by name.

Spring Bean Naming Conventions in Java-based config

Spring Bean Naming Conventions in an annotation-based config

8. Handle Circular dependencies

If you use predominantly constructor injection, it is possible to create an unresolvable circular dependency scenario.
For example - Class A requires an instance of class B through constructor injection, and class B requires an instance of class A through constructor injection. If you configure beans for classes A and B to be injected into each other, the Spring IoC container detects this circular reference at runtime and throws a BeanCurrentlyInCreationException.
public  class A {
    public A(B b){
       ....
    }
}
public  class B {
    public B(A b){
       ....
    }
}
One possible solution is to edit the source code of some classes to be configured by setters rather than constructors. Alternatively, avoid constructor injection and use setter injection only. In other words, although it is not recommended, you can configure circular dependencies with setter injection.

9. Exception Handling in Spring boot Rest API projects

Handle proper exceptions and custom error messages for RESTful Web Services developed using Spring Boot.

10. Follow Restful API Design Best Practices in Spring Boot Rest API Applications

I have written a separate article of Restful API design best practicesHere is a list of best practices to design a clean RESTful API.

Comments