I was wrong: Constructor vs. setter injection

Reading books or reference documentation is always good to get new ideas or to gain new insights.
While reading the Spring reference documentation, I realized I was wrong!

In one of my previous blog posts about Dependency Injection vs. Service Locator, specifically in the part “The final clash – Constructor vs. setter injection”, I said that I agreed with Martin Fowler.

Martin advocated the use of constructor injection as much as possible unless things are getting too complex. His advice is to use constructor injection to create valid objects at construction time. This advice originates from Kent Beck’s book Smalltalk Best Practice Patterns.
I myself have always used setter injection because that was the way I was taught to use Spring. But after reading Martin Fowler’s article, I agreed with having to use constructor injection more often.
In most circumstances, now I know I was wrong.

What are the problems with constructor injection?

No reconfiguration and re-injection

As the Spring reference documentation – Constructor-based or setter-based DI? states:

The Spring team generally advocates setter injection, because large numbers of constructor arguments can get unwieldy, especially when properties are optional. Setter methods also make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is a compelling use case.

Some purists favor constructor-based injection. Supplying all object dependencies means that the object is always returned to client (calling) code in a totally initialized state. The disadvantage is that the object becomes less amenable to reconfiguration and re-injection.

Use the DI that makes the most sense for a particular class. Sometimes, when dealing with third-party classes to which you do not have the source, the choice is made for you. A legacy class may not expose any setter methods, and so constructor injection is the only available DI.

So indeed, using constructor injection when no setters exist, you cannot reconfigure the constructed bean by injecting new dependencies into it.
If you want to “reconfigure” the bean, you’ll have to construct a new bean instance using the new dependencies and discard the other one.

Circular dependencies

Another problem occurs when you’re having circular dependencies.
Again, the Spring reference documentation – Circular dependencies states:

If you use predominantly constructor injection, it is possible to create an unresolvable circular dependency scenario.

For example: Class A requires an instance of class B through constructor injection, and class B requires an instance of class A through constructor injection. If you configure beans for classes A and B to be injected into each other, the Spring IoC container detects this circular reference at runtime, and throws a BeanCurrentlyInCreationException.

One possible solution is to edit the source code of some classes to be configured by setters rather than constructors. Alternatively, avoid constructor injection and use setter injection only. In other words, although it is not recommended, you can configure circular dependencies with setter injection.

Unlike the typical case (with no circular dependencies), a circular dependency between bean A and bean B forces one of the beans to be injected into the other prior to being fully initialized itself (a classic chicken/egg scenario).

While it’s not a recommended scenario, you could create a circular dependency using Spring. But not by using constructor-based injection. If you want to create a circular dependency, you’ll have to use setter-based injection.

I have an example of this, which can be downloaded through the following link: spring-setter-injection.zip
You’ll need Maven to build and run the example.

[UPDATE]
You’ll notice that the ConstructorBasedCircularDependencyTest does not fail.
Thanks to Mathew, I found a way of testing if the expected exception will occur. Instead of relying on the SpringJUnit4ClassRunner to create the ApplicationContext, I create the ApplicationContext myself inside the test method, and annotate the test method to expect the UnsatisfiedDependencyException, which wraps the BeanCurrentlyInCreationException.
[/UPDATE]

To end this post, I’ll quickly show how to use constructor-based injection and setter-based injection using Spring annotations.

Constructor-based injection:

@Component
public class A {
    private B b;

    @Autowired
    public A(B b) {
        this.b = b;
    }

    /**
     * @return the b
     */
    public B getB() {
        return b;
    }
}

Setter-based injection:

@Component
public class A {
    private B b;

    /**
     * @return the b
     */
    public B getB() {
        return b;
    }

    /**
     * @param b
     *            the b to set
     */
    @Autowired
    public void setB(B b) {
        this.b = b;
    }
}

So sometimes, when you get a new insight, you have to be able to acknowledge you were wrong about something.
I hope you all enjoyed reading this post. Feel free to post your comments below.

[UPDATE]
As I said before, a circular dependency is something that is to be avoided! But when you stumble upon one and you cannot refactor it out immediately, constructor injection is not going to work in that scenario. At least not with Spring.

But reading Petri’s post Why I Changed My Mind About Field Injection?, again gave me new insights. He does have a point and I think the same goes for setter injection.
When you do have a messy constructor or a lot of setters, it means that something is wrong with your class design and your separation of concerns. Probably, you need to refactor some behavior out of the class to a separate one.
By the way, field injection can make unit testing harder. Using constructor or setter injection, you can define the dependencies from within your unit tests and pass them to your constructor or setter.

Use constructor injection for mandatory dependencies and setter injection for the optional ones, but make sure your constructor doesn’t get messy and you don’t end up with a whole bunch of setters. If that is the case, take a look at the separation of concerns.
[/UPDATE]

About these ads

About Steve Schols

I am Steve Schols, a senior Java consultant working for several clients in Belgium. I mainly blog about the Java language and relevant frameworks and technologies. All statements made here are solely my own and do not represent the opinion of my employer, colleagues or my clients.
This entry was posted in Java, Object Oriented Design, Spring and tagged , , , , , , , , , , , . Bookmark the permalink.

15 Responses to I was wrong: Constructor vs. setter injection

  1. Daniel says:

    I tend to follow Steve Freeman’s and Nat Pryce’s approach in Growing Object-Oriented Software, Guided by Tests. Dependencies are in the constructor and configuration are provided defaults, with setters to override the default. Doing this, the user of the class will always get a valid object, and can still change configuration on the fly.

    I consider the fact that you cannot create circular dependencies as an advantage, not a problem. One is forced to come up with a better design.

  2. Steve Schols says:

    Hi Daniel, thanks for your comment.

    Indeed, I see where you’re going with mixing both principles. It is the best of both worlds.
    Unless ofcourse when you create circular dependencies, you’ll still have problems when using Spring.
    But circular dependencies aren’t an ideal situation nonetheless, that should be avoided, like you say in your comment.

    • Esteban says:

      Hi Steve,
      Nice article. What I would comment on “The Spring team generally advocates setter injection, because large numbers of constructor arguments can get unwieldy, especially when properties are optional” is that constructors are fine even if they have multiple arguments. However, if a class requires > 6 dependencies they you should probably check the class design. May be your class is doing to many things and you should decouple in smaller classes…

      • Steve Schols says:

        Hi Esteban

        You’re absolutely right. Sometimes I have to reflect on a topic a little bit further I guess :-)
        Too many dependencies can be a sign of breaking the single responsibility principle.
        Of course, a Service class can have multiple services or DAO’s as a dependency, but you can never have much more than a few.

  3. Pingback: Schauderhaft » Repeat After Me: Setter Injection is a Symptom of Design Problems

  4. Daniel (not the same Daniel as the earlier poster) says:

    I think the spring recommendations solutions in this case are a tad off. The biggest advantage of constructor-based injection is that it allows for immutable objects. When the constructor-arguments become unwieldy, I typically have spring use setter-based injection *on a builder object*, and use that builder as the sole constructor argument. This allows for complex objects as well as setter-based injection, as well as immutability.

    As for circular dependencies, the goal is minimize or eliminate them. They often represent poor organizational decisions.

    • Steve Schols says:

      Hi Daniel,

      Thanks for your reply. By all your guys replies, I get to learn new insights as well.

      I didn’t look at it that way yet, to create immutable objects or to use the builder pattern to have setter injection. I’ve read something about that in some article or the reference doc itself.
      Normally, Spring only allowed basic JavaBean-style setters that return void, but nowadays Spring removed this limitation, and you can use builder-style setters as well.

      Circular dependencies do need to be avoided indeed. The example just shows that Spring prohibits you from using them. It’s not that I was saying that prohibiting circular dependencies is a bad thing :-)

  5. Nice post. Thanks for sharing :].

    I agree with Daniel (the first comment) that in most cases constructor injection should be used for default values and setter injection for optional values.

    About your question:
    Do you, as a reader of my blog, know of a way to accomplish also expecting exceptions at initialization time and flagging them to allow the test to succeed?

    The simplest solution is to write a test class that is not run with Spring JUnit runner (ommit the @RunWith) and try to create a Spring application context yourself. Then you can add @Test(expected=…).

    • Steve Schols says:

      Damn :-), of course, you’re right.

      Instead of using the Spring JUnit runner, just make a test method and create the ApplicationContext from within that method. I did that in one of my previous examples.

      I always try to use automatic configuration, so I didn’t think of this easy solution.

      Thanks.

  6. stijnvp says:

    Steve,

    When you put the @Autowired annotation on your instance variables you don’t need neither of them.

    I agree that Spring handles setters injection better (when you’re not using Autowired annotations but using xml or javaconfig) especially when you’re doing some refactoring. BUT if I put on my OO hat, and I don’t want that my code depends on Spring I would always favor constructors. So for me the discussion is mainly about choosing between what’s the best for Spring or what’s the best for your code. What would you do if you wrote your code without Spring?

    I believe if you choose to adapt your code to Spring you might as well use @Autowired or @Inject on instance variables like said before. You can always make your code Spring and CDI compliant.

    Btw if you have to many arguments in your constructor than you’ll possibly have to many dependencies and your class might not have a single responsibility then you’ll have something more important to think about then setter or constructor injection ;-). And like said before circular dependencies are evil.

  7. Pingback: Cyclic Dependency Injection and Making a Choice | Tim's Blog

  8. Javame says:

    In my opinion use Setter only for optional dependency as mentioned on How to choose between Setter vs Constructor dependency Injection

  9. It is worth mentioning that the Spring team has changed their mind long time ago, unfortunately the breakout box you quote has never been updated. This is about to be fixed now:

    https://jira.springsource.org/browse/SPR-11459

    • Steve Schols says:

      Hi Erich,

      Thanks for your reply and the JIRA link.

      Indeed, I started reading more and more about constructor injection: the use of mandatory dependencies and easier testable code. So I always wondered why Spring did advocate setter-injection. Apparently, they changed their mind as well.
      Mostly I use field injection, but that can make the code less testable.

      Either way, circular dependencies are considered bad design and are to be avoided. And in Spring that is covered correctly by throwing an Exception when circular dependencies are detected if you use constructor injection.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s