Elegant solution of Spring dependency injection

Posted by iriedodge on Mon, 03 Jan 2022 16:49:11 +0100

I am Xiao Hei, a programmer who "lingers" on the Internet

Pay attention to the official account of the same name [Xiao Hei Java], more dry cargo content is served first, and more occasional lottery offers.

Running water doesn't compete first. It's important to talk

In this article, I'll show you how to use Project Lombok as a best practice for Spring framework dependency injection.

preface

The Spring framework itself has various ways to perform dependency injection. Flexible choice is the strength of the Spring framework. However, not all dependency injection methods are considered best practices.

Dependency injection

Next, we use some code examples to implement various dependency injection methods of Spring. First, we have a MyService. There is a sayHi() service in this service. We try to inject it in different ways in the Controller.

@Service
public class MyService{
    public String sayHi() {
        return "hello Spring.";
    }
}

Attribute injection

@Controller
public class FieldController {

    @Autowired
    private MyService service;

    public String saySomething() {
        return service.sayHi();
    }
}

Through attribute injection, Spring will inject through reflection when allocating beans. Although this method can meet the dependency injection, during testing, you either need to start the Spring Context or use some Spring utilities to perform dependency injection for testing.

We can improve this by providing setters for private properties. Getters and setters are generally considered best practices in object-oriented programming. It is very simple to annotate setter methods to guide Spring to use setters for dependency injection.

Method injection

@Controller
public class FieldController {

    private MyService service;

    @Autowired
    public void setService(MyService service) {
        this.service = service;
    }
    
    public String saySomething() {
        return service.sayHi();
    }    
}

This is an improved way to use private attribute injection, but some people still think there is too much code.

Constructor Injection

When using constructors to inject properties, you must provide the @ Autowired annotation. This is a good function. It reduces some code for us. Since Spring Framework version 4.2, constructor annotations for dependency injection have been optional.

@Controller
public class FieldController {

    private MyService service;

    public FieldController(MyService service) {
        this.service = service;
    }
    public String saySomething() {
        return service.sayHi();
    }
}

Constructor based dependency injection is generally considered a best practice. For a while, I personally liked setter based injection, but later I turned to constructor based injection.

At present, there are two main problems in the injection method based on constructor.

  • The types of our services are specific. Hard typed dependency injection is not considered a best practice.
  • The attribute we want to inject is not declared final. Therefore, theoretically, the injected attribute can be modified after instantiation.

Dependency injection best practices

The best practice for dependency injection is to use interfaces, constructors, and final attributes.

Best practice service interface

public interface BpService {
    String getHello();
}

Best practice service implementation

@Service
public class BpServiceImpl implements BpService{
    @Override
    public String getHello() {
        return "The Best Hello!";
    }
}

Using Lombok

Next, the reasons for using Lombok project in dependency injection are:

  • Declare the final attribute of the interface type
  • Use the args constructor annotation required by Lombok

Lombok Controller

@Controller
@AllArgsConstructor
public class BpController {
    private final BpService bpService;
    public String saySomething() {
        return bpService.getHello();
    }
}

This is a good way to keep the code very clean. When using Spring, you often need several automatically injected properties. When you need to add a bean, you only need to declare the property as final. There is no need to add @ Autowired annotation, setter method or constructor.

I've been using this approach in everyday coding for some time. This is definitely a time-saving thing, and the code will become clear.

Summary

In this issue, I shared with you different ways of Spring dependency injection, mainly including:

  • Inject through the private attribute Autowired;
  • Inject through setter method;
  • Injection through the constructor;

However, these three methods are not best practices. The best practice I recommend is to use Lombok's @ AllArgsConstructor annotation and define the bean to be injected as the final attribute.

I hope it will be helpful to your development. A praise is my greatest support.

I am Xiao Hei, a programmer who "lingers" on the Internet

Pay attention to the official account of the same name [Xiao Hei Java], more dry cargo content is served first, and more occasional lottery offers.

Running water doesn't compete first. It's important to talk

Topics: Java Spring Back-end