Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly do dependency injection (in Spring)? [duplicate]

I have a doubt about injecting objects to a class using Spring. I used in my projects this kind of code:

@Resource // or @Autowired even @Inject private PersonRepository personRepository; 

then used it normally on methods as :

personRepository.save(p); 

Otherwise I found on Spring examples, injecting the constructor:

private final PersonRepository personRepository;  @Autowired public PersonController(PersonRepository personRepository) {   this.personRepository = personRepository; } 

So both are correct? Or each on has its properties and usages?

like image 230
Joao Evangelista Avatar asked Jun 21 '14 01:06

Joao Evangelista


People also ask

What is the right way to inject dependency?

Constructor injection should be the main way that you do dependency injection. It's simple: A class needs something and thus asks for it before it can even be constructed. By using the guard pattern, you can use the class with confidence, knowing that the field variable storing that dependency will be a valid instance.

Which dependency injection is better in Spring?

Setter-Based Dependency Injection We can combine constructor-based and setter-based types of injection for the same bean. The Spring documentation recommends using constructor-based injection for mandatory dependencies, and setter-based injection for optional ones.

What is Spring dependency injection explain with suitable example?

The Spring-Core module is responsible for injecting dependencies through either Constructor or Setter methods. The design principle of Inversion of Control emphasizes keeping the Java classes independent of each other and the container frees them from object creation and maintenance.


1 Answers

tl;dr - Constructor injection is the best way of doing DI

The latter is correct and this is not so much because of Spring or any dependency injection container, but object-oriented class design principles.

Details

A type should be designed, so that you can only create instances from it, that are in a valid state. To achieve this, all mandatory dependencies of that type need to be constructor arguments. This means, these dependencies can be null-checked, assigned to final fields to promote immutability. Beyond that, when working with the code, for the caller (or creator) of that instance it's immediately obvious which dependencies it has to provide (through either skimming through the API docs or using code completion in the IDE).

All of this is impossible with field injection. You don't see the dependencies from the outside, you require some black magic to inject the dependencies and you can never be sure they're not null except you blindly trust the container.

The last but not least important aspect actually is, that with field injections, it's less painful to add a lot of dependencies to your class, which is a design problem in itself. With constructors that becomes much more painful much earlier which is a good thing as it tells you something about your class design: the class has too many responsibilities. No need to calculate metrics on it in the first place, you feel it when you try to extend it.

Containers

People often argue that that's just academic bullshit as you can rely on the container anyway. Here's my take on this:

  • Just because a container exists, it doesn't mean you have to throw all basic object-oriented design principles over board, does it? You still take a shower, even if antiperspirants exist, right?

  • Even types designed for usage with a container, will be used manually: in unit tests. If you don't write unit tests… well that's another topic then.

  • The alleged verbosity of an additional constructor ("I can achieve the same thing with a single line of field injection!!" - "No you can't. You actually get stuff from writing a line of code more.") can be mitigated by things like Lombok. A constructor injected component with Spring and Lombok looks like this:

    @Component @RequiredArgsConstructor class MyComponent implements MyComponentInterface {    private final @NonNull MyDependency dependency;    … } 

Lombok will take care of generating a constructor taking a parameter for each final field and check the given parameter for null before assigning it. So you effectively get the brevity of field injection and the design advantages of constructor injection.

Epilogue

I been part of a discussion recently with some non-Java folks that I terribly puzzled by using the term "injection" for constructor DI. Effectively, they argued - and there's a lot of truth to that - that passing dependencies through a constructor is not injection at all, as it's the most natural way to hand objects into others (in stark contrast to injections of any sorts).

Maybe we should coin a different term for that kind of style? Dependency feeding, maybe?

Resources

  • Oliver Gierke - Why field injection is evil
  • Jens Schauder - The one correct way to do dependency injection
like image 125
Oliver Drotbohm Avatar answered Oct 08 '22 12:10

Oliver Drotbohm