Home > Java > My case against autowiring

My case against autowiring

Autowiring is a particular kind of wiring, where injecting dependencies is not explicit but actually managed implicitly by the container. This article tries to provide some relevant info regarding disadvantages of using autowiring. Although Spring is taken as an example, the same reasoning can apply to JavaEE’s CDI.

Autowiring basics

Autowiring flavors

Autowiring comes into different flavors:

  • Autowiring by type means Spring will look for available beans that match the type used in the setter. For example, for a bean having a setCar(Car car) method, Spring will look for a Car type (or one of its subtype) in the bean context.
  • Autowiring by name means Spring search strategy is based on beans name. For the previous example, Spring will look for a bean named car regardless of its type. This both requires the bean to be named (no anonymous bean here) and implies that the developer is responsible for any type mistmatch (if the car bean is of type Plane).

Autowiring is also possible for constructor injection.

Autowiring through XML configuration

Let’s first dispel some misconceptions: autowiring does not imply annotations. In fact, autowiring is available through XML since ages and can be enabled with the following syntax.

<bean autowire="byType" class="some.Clazz" />

This means Spring will try to find the right type to fill the dependency(ies) by using setter(s).

Alternative autowire parameters include:

  • by name: instead of matching by type, Spring will use bean names
  • constructor: constructor injection restricted to by-type
  • autodetect: use constructor injection, but falls back to by-type if no adequate constructor is found

Autowiring through annotations configuration

Available annotations are the following:

Annotation Description Source
 org.springframework.bean.factory.@Autowired  Wires by type  Spring 2.5+
 javax.annotation.@Resource  Wires by name  JavaEE 5+
 javax.inject.@Inject  Wires by type  JavaEE 6+
javax.inject.@Qualifier  Narrows type wiring  JavaEE 6+

Dependency Injection is all about decoupling your classes from one another to make them more testable. Autowiring through annotations strongly couples annotated classes to annotations libraries. Admittedly, this is worse for Spring’s @Autowired than for others as they are generally provided by application servers.

Why it is so bad after all?

Autowiring is all about simplifying dependency injection, and although it may seem seductive at first, it’s not maintainable in real-life projects.

Explicit dependency injection is – guess what, explicitly defining a single bean to match the required dependency. Even better, if Java Configuration is used, it is validated at compile time.

On the opposite, autowiring is about expressing constraints on all available beans in the Spring context so that one and only one matches the required dependency. In effect, you delegate wiring to Spring, tasking him to find the right bean for you. This means that by adding beans in your context, you run the risk of providing more than one match, if your previous constraints do not apply to the new beans. The larger the project, the larger the team (or even worse, the number of teams), the larger the context, the higher the risk.

For example, imagine you crafted a real nice service with a single implementation, that you need to inject somewhere. After a while, someone notices your service but creates an alternative implementation for some reason. By just declaring this new bean in the context, along with the former, it will break container initialization! Worse, it may be done in an entirely different part of the application, with seemingly no link with the former. At this point, good luck to analyze the reason of the bug.

Note that autowiring by name if even worse, since bean names have a probability of collision, even across different type hierarchies.

Autowiring is bad in Spring, but it is even worse in CDI where every class in the classpath is a candidate for injection. By the way, any CDI guru reading this post care to explain why autowiring is the only way of DI? That would be really enlightening.

Summary

In this post, I tried to explain what is autowiring. It can be used all right, but now you should be aware of its con. IMHO, you should only use it for prototyping or quick-and-dirty proof of concepts, everything that can be discarded after a single use. If really needed, prefer wiring by type over wiring by name as at least it matching doesn’t depend on a String.

email
Send to Kindle
Categories: Java Tags: , ,
  1. November 4th, 2013 at 01:04 | #1

    Hi Nicolas,
    I think I see your point but what I don’t get is that even if there are multiple implementations of a given interface (maybe specific ones for tests or different app profiles), you should only have only one defined at a given time in the context. As long as you don’t use component scanning (in Spring), new instances won’t automagically be inserted in the context when another class defining the interface will be created.
    As long as you take care of what’s defined in your context, I don’t really see the point…

  2. November 4th, 2013 at 17:24 | #2

    in CDI an extension is allowed to veto beans so it is technically feasible to achieve it.

  3. November 5th, 2013 at 14:34 | #3

    @Julien Viet
    Thanks for the tip, I’ll look into it

  4. Maik Jäkel
    November 6th, 2013 at 08:39 | #4

    Hi Nicolas,

    you wrote
    “For example, imagine you crafted a real nice service with a single implementation, that you need to inject somewhere. After a while, someone notices your service but creates an alternative implementation for some reason. By just declaring this new bean in the context, along with the former, it will break container initialization!”

    At least for Spring this does not apply if you specify @Primary on your service implementation. When someone else implements the service as well, your implementation will still be the one being autowired and the initialization won’t break!

    I get your point that Autowiring gives you less safety about the correctness of your compiled code. From my experiences however, Autowiring default implementations is not a behaviour that breaks the software. Usually it is the absence of a service and that can’t be fixed by declaring a service name, either.

  5. Maik Jäkel
    November 6th, 2013 at 08:41 | #5

    @Maik Jäkel
    All of the above of course is based on the assumption of a global component scan, which you shouldn’t do anyways. Other than that Francois’ point should be valid.

  6. November 18th, 2013 at 20:18 | #6

    IMO Spring is useless nowadays.
    And I don’t think you know CDI enough to make a parallel with Spring so easily. Let me give a few precisions:

    I haven’t touched Spring in a while but I’m a CDI user since its inception and I can promise you it runs on real life applications that are totally maintainable (and I’d even say better maintenable than when they were on EE5 or with Spring). I know one project where we saved 70.000 lines of code when we switched to CDI. And it’s running faster now.

    Like with every technology you have to use it wisely. It’s not because you CAN use CDI and it allows @Qualifier’s and @Alternative’s (and @Produces, and @Stereotype and @InjectionPoint, etc) that you should use the whole works in each and every class. Personally I mainly use @Inject to inject services/dao’s/ejbs; and I scarcely use @Qualifier with @Produces to obtain specifically “shaped” instances (that I wouldn’t have with a simple @Inject). And the same goes with @Alternative which are meant for specific purposes (eg testing).

    Regarding the danger of alternatives or collisions, you overlook the fact CDI implementations perform a thorough consistency check at startup with precise reporting. Also, @Alternatives are not activated by default and we still have @Veto as another user pointed out. It’s a non-issue. As for name-based wiring, the CDI BeanManager has an EL resolver but I have never met anyone sane using it to retrieve a @Named reference. Once again you don’t HAVE to use all the features of a given framework. I clearly remember Gavin King warning the audience in a conference a few years ago, about the misuse of the power CDI gives to the developper.

    You’re asking why autowiring is the only way of DI in CDI. Well, you can explicitly ask for a reference from the BeanManager in CDI, but then you have bean references that have no “CreationalContext”, thus are not really managed by the container and you face the risk of leaking references. The CDI doc explains it better than me I remember.

    Makes me think your post totally conceals is the C(ontext) in CDI. OK it’s about autowiring/DI in the first place (that is what CDI and Spring have in common) but it gives a kind of biaised/simplistic view of what this kind of technology is about. It’s never been easier to inject anything from a given scope into something else, and let the CDI container manage the beans/resources and their lifecycle according to this of the Web container for example. Here again, like with every technology, you have to think when you type so as not to bloat the session for example.

  7. Saad EL Khlifi
    November 27th, 2013 at 17:56 | #7

    I thing that trying to shield everything with configuration and sometimes trying to do that from the compilation stage will quickly lead the project to unmanageable situation in terms of complexity.
    The best choice in my opinion would be to find a compromise between the configuration and the Convention: The Convention over configuration principle
    For me autowiring remain a good technique to inject beans, and the good practice is to drive it with the appropriate conventions and practices

  8. JustJoe
    January 20th, 2014 at 17:01 | #8

    Like a great many things in software development, if you do it wrong, it is indeed bad. Autowiring probably falls into this usage class as much as anything. However, if you don’t use XML configuration and only use Java Config, then autowiring can be very effective. In such usage, the @Autowired annotations should ONLY go into @Configutation annotated classes. That is, NONE OF THE BEANS MEMBERS should have @autowired. Used in a such a manner, the Beans become pure POJOs, (members can all be declared ‘final’) and are as decoupled from one another as the design permits.

  9. skay
    October 26th, 2014 at 13:30 | #9

    Hi,

    “adding beans in your context, you run the risk of providing more than one match”
    -> This is true, and the container initialization will crash / as you mentioned. And this is the only way to keep control / on the underlying risk you describe here !

    If you need to control the specific alternative of some injected bean interface, you need to provide the underlying @produce method.

    So what is the problem ?

  10. October 26th, 2014 at 17:14 | #10
    1. In real-world applications with many developers, one change in a part of the application will break something in another part. This is very hard to debug
    2. Explicit wiring has no such problem
    3. What’s the real advantage of autowiring?
  1. No trackbacks yet.