Search This Blog

Saturday, 3 March 2012

Injecting Properties Of Beans

Simply creating beans is not the only work of the container. We also need it to able to configure the newly instantiated beans. We need to 'inject dependencies' into these beans. There are two ways to inject the bean properties. One is using
the setter method injection:
Consider the Musician class below which has one property -'instrument'. Like any bean class, it includes simple getter setter methods to control the value.
public class Musician implements IPerformer {
    private String instrument;

    public String getInstrument() {
        return instrument;
    }

    public void setInstrument(String instrument) {
        this.instrument = instrument;
    }

    public void perform() {
        System.out.println("Playing instrument " + instrument + "...");
    }
}
The XML configuration for creating the bean is as below:
<bean id="musician1" class="com.performer.Musician">
    <property name="instrument">
        <value>Guitar</value>
    </property>
</bean>
When the Spring Container creates the musician object(using the default constructor), it calls the setInstrument() methods to set the value "Guitar". If we were to create the object
public static void main(String[] args) {
    XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
    IPerformer musician = (IPerformer) beanFactory.getBean("musician1");
    musician.perform();
}
The output is as below:
Creating new Musiscian Object com.performer.Musician@1f4689e
Playing instrument Guitar...
The above XML configuration can be further simplified:
<bean id="musician1" class="com.performer.Musician">
    <property name="instrument" value="Guitar"/>
</bean>
If the property was another bean and not a literal then the ref attribute would be used. Assume that the Instrument property was a class and not a string value, then the bean configuration would be as below:
<bean id="guitar" class="somepackage.Instrument"/>
<bean id="musician1" class="com.performer.Musician">
    <property name="instrument" ref="guitar"/>
</bean>
In this case the ref attribute refers to an instrument object.
The second technique is to use construction injection. I modified the Instrument class to include some constructors.
public class Musician implements IPerformer {
    private String instrument;
    
    public Musician(final String instrument) {
        System.out.println("Creating new Musician Object " + toString()
                + " and instrument " + instrument);
        this.instrument = instrument;
    }
    public void perform() {
        System.out.println("Playing instrument " + instrument + "...");
    }
}
The xml configuration for the bean would be:
<bean id="musician3" class="com.performer.Musician">
    <constructor-arg>
        <value>Violin</value>
    </constructor-arg>
</bean>
The shortened format for the above is:
<bean id="musician3" class="com.performer.Musician">
    <constructor-arg value ="Violin" />
</bean>
In case of a bean reference the ref attribute is used.
The problem with constructor arguments arises when there are multiple constructors involved and the function signature is not clear:
public class Musician implements IPerformer {
    private String instrument;
    
    public Musician(final String instrument) {
        System.out.println("Creating new Musician Object " + toString()
                + " and instrument " + instrument);
        this.setInstrument(instrument);
    }

    public Musician(final Short age) {
        System.out.println("Creating new Musician  " + toString()
                + " of age " + age);
    }
    
    public Musician(final Integer id) {
        System.out.println("Creating new Musician Object " + toString()
                + " of id " + id);
    }
//...
If I used the below configuration,
<bean id="musicianI" class="com.performer.Musician">
    <constructor-arg  value="1"  />
</bean>
then the output is as below:
Creating new Musician Object com.performer.Musician@14a8cd1 and instrument 1
As can be seen the constructor for String was called. To ensure that the right constructor is called
<bean id="musicianI" class="com.performer.Musician">
    <constructor-arg  value="1"  type="java.lang.Short"/>
</bean>
The type argument indicates the class of the parameter. There is also an index argument available(not useful in above case):
<bean id="musicianI" class="com.performer.Musician">
    <constructor-arg  value="1"  index="0"/>
</bean>

No comments:

Post a Comment