Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't Spring support direct field dependency injection (except for autowired)?

Tags:

I am interested in direct field dependency injection. Traditionally, Spring supports both constructor injection (supplying arguments to constructors) and setter-based injection (calling setters on a call).

However, Spring is also capable of direct field injection (setting member fields of an object without a setter method), as evidenced by annotating fields with @Autowired. Autowiring is limited to just "beans", so primitive values cannot be injected (although this can somewhat be circumvented by creating beans of class "java.lang.String" - this works, but has the normal caveats of autowiring.) In addition to this, Spring supports @Value to directly set values to member fields from properties etc.

Yet, Spring does not allow properties to be directly set to member fields (without autowiring).

My question is: why?

It is obviously capable of doing so, so why doesn't it? Are there any big negative side-effects that prevent this? Or is the capability somehow limited so that only autowiring makes sense? Does it need some bigger hacks than calling setters?

Note that I do not wish to discuss the relative merits of having setters and getters in general, just the reasons why Spring has made this choice.

like image 661
Nakedible Avatar asked Mar 25 '11 13:03

Nakedible


2 Answers

The @Autowired annotation uses reflection to make private fields accessible (see this related question). I can see three things why it isn't used in Spring configuration files.

  1. Since configuration happens by bean properties (getters and setters) you can't really tell - in the likely case that both exist - if you want to e.g. call setValue or set the member value.
  2. It breaks encapsulation. Your Spring configuration has no reason to know about private member variables. With an annotation that's ok since it is already right there in the source code.
  3. Security concerns. A more restrictive security manager might not allow making private fields accessible via reflection.
like image 106
Daff Avatar answered Nov 03 '22 20:11

Daff


I think I found the answer myself. I went over to the Spring source code and saw how the features were actually implemented. This is what I found:

Setting properties via XML is probably the oldest part of Spring, and it relies very heavily on "java.beans" classes for introspection, property enumeration, etc. And quite obviously, those do not support field introspection at all. On top of this is the type conversion machinery which determines how the property value can be converted to a suitable value for the property in question. There are no neatly separable pieces here.

All the @Autowired etc. stuff is implemented in a BeanPostProcessor, which has it's own type matching mechanic, which has nothing to do with the type conversion. That is also why it only injects beans. Same thing pretty much for @Value, it is just something that is resolved on the spot there and has nothing to do with properties.

So, adding field injection support, for properties in particular, is not a trivial engineering effort as the parts of the code that do one or the other are pretty much completely separate.

This doesn't exactly answer "Why?", but I think this is a more compelling explanation as to why Spring hasn't added direct field dependency injection than the other explanations I've heard. Unless they have something fundamental against it (which I doubt, considering that they want to allow configuration of existing third party classes, not just JavaBeans), then it's just a matter of engineering effort to get the functionality in.

like image 36
Nakedible Avatar answered Nov 03 '22 21:11

Nakedible