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?
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.
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.
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.
The latter is correct and this is not so much because of Spring or any dependency injection container, but object-oriented class design principles.
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.
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.
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?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With