By Peter Bell

Constructor vs. Setter Injection: Constructor is Better

What is the difference between constructor and setter injection, and which should you use when?

Dependency Injection 101 With a Dependency Injection (DI) engine like ColdSpring or LightWire, you ask the engine to provide the properties and objects that your objects need to function correctly. So, if your UserService needs to be able to speak to your UserDAO, you ask the DI engine to “inject” a reference to UserDAO into UserService so your UserService won’t have to worry about how to speak to the user DAO.

This provides a number of benefits. Over time as different objects depend on other objects in long dependency chains, automated dependency resolution (“gee, if I want a UserService, first I need to create a UserDAO, but before I can create that I need to create a DataSource object as UserDAO needs to have that to function”) can save a bunch of headaches. Also, the beans you are injecting know nothing about how they get their dependencies, so while they are clearly dependent on something to provide them with the objects and properties they require, it doesn’t have to be your DI engine. This makes it nice and easy to test the cfc’s using unit testing, manually providing any required properties and mock objects as part of the “fixture” part of your unit test cfc’s.

Constructor vs. Setter Injection With constructor injection, you inject a property or object into the init() method of the object. With setter injection, you create a method called set%ObjectName%() which allows that object to be injected after initialization.

Circular Dependencies The biggest benefit of setter injection is that it allows for circular dependencies. Circular dependencies are actually pretty common. If you have a UserService that needs to get information about an employer from CompanyService and the CompanyService needs information about employees from UserService, right there you have a circular dependency. In general I find a lot of circular dependencies between service methods, but with complex object models it is possible to have circular dependencies elsewhere.

Which is Best? There is no definitive right answer, but I tend to prefer constructor injection as setter injection feels a little “hacky” to me. Why? Well, the whole point of a constructor (in ColdFusion, we use the init() method by convention as our constructor) is to provide a clear definition of the requirements of an object. You should be able to look at the arguments of your init() method and know that if you want to use that object, those are the elements that you have to provide for that object to operate correctly.

Setter injection violates that by adding an undocumented requirement that if you want the object to work you also have to inject it with one or more objects immediately after construction. It also confuses the API of the object by adding public methods (such as setUserDAO() for setter injecting a User DAO) which are really not part of the object API. You don’t really want people to be injecting UserDAOs into your UserService – it is just something you have provided for your DI engine.

Consistent Conventions However, the only thing worse that using setter injection more than necessary is not having a consistent set of rules for choosing between constructor and setter injection. I’d rather see a project that only used setter injection than one that used a random combination of the two methods.

Setter injection must be used for circular dependencies. I have found that the only circular dependencies I have come across to date are between service methods (this is as much an architectural choice as anything else – I see why service methods could have valid circular dependencies, but elsewhere in my model I try to avoid such circularities). Because of this I follow a convention that I use setter injection between service methods and constructor injection for all other methods.

Anyone else got any conventions or rules of thumb they use for selecting between constructor and setter injection?

Comments
I generally use constructor injection for the reasons you mentioned (mostly for good documentation of dependencies). I rarely have any circular dependencies that I can't avoid by refactoring the application.

If I do, I go ahead and add a method for setter injection (which I try to document copiously).
# Posted By Steve Bryant | 11/18/06 4:45 PM
If you accept that nobody but UserService has any business calling UserDAO, you can at least make the setter injection methods package-visible.
# Posted By Jaime Metcher | 11/18/06 5:43 PM
IMO, setter injection is a better rule of thumb to follow.

1. Unless you throw setters into a component in random places throughout it -- the documentation argument isn't very compelling. As long as you group your setters that perform injection just below your init - I can't foresee why it's any different to read documentation wise.

2. Applications change. Whilst you may not have a circular dependency now, as your application evolves -- things change! You can save yourself a bit of refactoring in the future (and trust me I learned this one in the real world).

Lastly, as a rule of thumb. If it is required when the component is init'ed, use constructor arg. If it is not, then use setter injection. Default to setter injection unless you run into problems...

Example, it's a requirement that you need to parse data from an xml file immediately - then set the location of the xml file via constructor. Everything else is gravy...
# Posted By Peter J. Farrell | 11/19/06 4:23 AM
@Steve - pretty much what I'm doing although I'm also adding a new mixin injection option to LightWire - will blog about that later!

@Jamie - Good point, although as it is the DI engine that runs the setter I don't know if that would work (as in I don't know not as in I think it wouldn't)!

@Peter - I don't do this, but I buy the approach in as much as apps do change and I think uncertainty as to whether something is setter or constructor is worse than it all being setter. Also, you could dump the constructor injection entirely and more your initialization code into init-method (usually setup()) if you wanted to as that is run after all setter injections from what I understand.
# Posted By Peter Bell | 11/19/06 3:07 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.005.