tags:

views:

899

answers:

7

In spring you can initialize a bean by having the applicationContext.xml invoke a constructor, or you can set properties on the bean. What are the trade offs between the two approaches? Is it better to have a constructor (which enforces the contract of having everything it needs in one method) or is it better to have all properties (which gives you flexibility to only inject selectively for example when unit testing.)

What are the trade offs (between writing a bean that uses a constructor to establish it's initial state, or using properties and perhaps an afterProperties() method) ?

+5  A: 

This is a rather good post about constructor vs properties for Spring Beans. It focuses on checking required dependencies.

Feet
+2  A: 

IMO the major advantage of constructor injection is that it is compatible with immutability. However, if a class has more than about 3 dependencies, this requires providing a constructor which takes a large number of parameters, which is unwieldy.

When using setter-injection, I prefer to use the @PostConstruct annotation to identify the initialization method. This involves looser coupling to the Spring framework than the afterProperties() method you mention (actually, I think it's afterPropertiesSet()). Another option is the init-method attribute of the element.

Don
+11  A: 

I'm not sure there is a "best" way to initialize a bean. I think there are pros and cons to each, and depending on the situation, one or the other might be appropriate. This certainly isn't an exhaustive list, but here are some things to consider.

Using a constructor allows you to have an immutable bean. Immutable objects are good if you can fit them in your design. They don't require copying, serialized access or other special handling between threads. If you have setters, your object isn't immutable. Using a constructor also ensures the object is properly initialized. After the constructor finishes, the object is valid. If your object requires the use of setters to initialize it, it's possible to have an invalid object.

On the other hand, using constructors often leads to a telescoping problem. Often times you'll need many different constructors, most of which will be a superset of another constructor. Often times these are for convenience. For instance:

public class Person {
  public Person(String name) { ... }
  public Person(String name, String phone) { ... }
  public Person(String name, String phone, String email) { ... }
}

One alternative to this that I very much like is the so called "enhanced" builder pattern presented by Josh Bloch at JavaOne. You can see this in his book "Effective Java, Second Edition". If you look at the way the pattern is used, it will also solve your "afterProperties" method issue. The builder pattern will guarantee the object is correctly initialized.

Here is an additional blog post discussing the pattern: http://www.screaming-penguin.com/node/7598

I'm not sure this fits into your spring requirement, but in general, I'm a big fan of builder.

lycono
+1 - Really good answer
Andy White
i like your answer, but your links are dead :/
Maxime ARNSTAMM
Thanks Maxime, I updated the post with the one link that still remains. :-)
lycono
+2  A: 

I don't know the version you are currently using, but if it is Spring 2.5 you could also consider using the @Autowired annotation for certain cases. This of coarse only works for references to other beans and not for Strings etc. as in lycony's example.

It saves you the burden of creating setters and/or constructors and a lot of configuration. A little Example:

public class MyPersonBean {
  @Autowired
  private PersonManager personManager;

  public void doSomething() {
    this.personManager.doSomething();
  }
}

And in your config file:

<context:annotation-config/>

Autowiring is done by type, so if you have a bean of the type PersonManager, it will inject it in the annotated field. In case you have more beans of that type you can use the @Qualifier annotation to tell them apart...

You can find more info about autowiring in the Spring Reference Documentation

I started using @Autowired in combination with component-scanning in my previous project and I must say that I got rid of more than 90% of my Spring configuration files.

Jaap Coomans
A: 

The tradeoffs:

Constructor: Benefits: Can be very simple, esp. with three or less properties to initialize. One-shot, no/minimal extra configuration to worry about.

Drawbacks: Multiple constructors must be created for several situations Constructors aren't inherited, so classes must call super() and provide duplicate constructors to allow the previous behavior.

Setters: Benefits: Children inherit setters, so properties can be easily overridden to influence behavior after construction. Multiple properties may be specified in a unified fashion without looking up different method signatures (JavaBeans conventions)

Drawbacks: Every setter must be invoked explicitly for every property. Leads to some classes having large numbers of properties explicitly set.

MetroidFan2002
A: 

You can also use @Resource to autowire instead of @Autowired, this works kinda like autowire byName so you don't have to worry if there are more beans with the same type (ofc you can also handle that with @Qualifier, but i would only recommend that to describe a characteristic of a bean). It really depends on your use case which way will be the best so you have to evaluate it for your situation and decide after.

kukudas
A: 

You can also use init-method. This is called after the properties are set.

Fortyrunner