Search This Blog

Tuesday, 7 February 2012

Identifying Beans - Name or Id

In the previous post we saw Spring and its relation to the term Beans. Now to look at beans from the implementation perspective. The first question is how to identify a Bean?
Beans in the xml file can be identified by their name or id property. For this post and a few others we shall use the below interface:
package com.performer;

public interface IPerformer {
    void perform();
}
As an implementation class I used the Singer class below:
package com.performer;

public class Singer implements IPerformer {

    private String song;       
    public Singer() {
        System.out.println("Creating a singer instance " + this.toString());
    }
    public String getSong() {
        return song;
    }
    public void setSong(String song) {
        this.song = song;
    }

    protected void sing() {
        System.out.println("singing " + song + "....");
    }

    @Override
    public void perform() {
        this.sing();
    }
}
I created a configuration file to hold a combination of beans with id and names.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean name="noId" class="com.performer.Singer" />
    <bean id="noName" class="com.performer.Singer" />

    <bean name="noId1;noId2" class="com.performer.Singer" />

    <bean id="singer" name="singerAlias1,singerAlias2" class="com.performer.Singer" />
    
    <!-- 
        This will not be allowed
        <bean name="noName" class="com.performer.Singer" />
        <bean id="noId" class="com.performer.Singer" />
     -->
    
</beans>
The above file contains a mix of beans, some identified by name and some by id. The first bean has no id while the second one has a name only. They both can be identified by the Spring Container. If I execute the below code:
public static void main(String[] args) {
    final XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("bean-identifier.xml"));
    final IPerformer noIdSinger = (IPerformer) beanFactory.getBean("noId");
    System.out.println("no Id Singer is " + noIdSinger);
    final IPerformer noNameSinger = (IPerformer) beanFactory.getBean("noName");
    System.out.println("no Name Singer is " + noNameSinger);
}
On executing the below code:
Creating a singer instance com.performer.Singer@13f3045
no Id Singer is com.performer.Singer@13f3045
Creating a singer instance com.performer.Singer@19209ea
no Name Singer is com.performer.Singer@19209ea
As can be seen from the output the bean factory was successfully able to locate either of the beans and create instances of them.
So what is the difference between two ?
Both id and name attributes refer to identifiers. The identifiers needs to be unique within the Spring container.
A bean will almost always have only one identifier, but if a bean has more than one identifier, the extra ones can essentially be considered aliases.
Why use ID ?
The id attribute allows you to specify one id. It is also marked in the XML DTD  as a real XML element ID attribute. In this case the XML parsers we use are able to do some extra validation when other elements point back to this one. This makes it the preferred way to specify a bean id.
Why use NAME ?
There could be a scenario wherin we need the same bean to have multiple identifiers. Just as we have multiple references to the same java object. This cannot be achieved using the id attribute. Any other additional identifiers need to be assigned using the name attribute. They are referred to as aliases to the bean. We can specify them separated by a comma (,) or semicolon (;) .
public static void main(String[] args) {
    final XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("bean-identifier.xml"));    
    System.out.println("Is singer Bean(alias 1) present ? " + beanFactory.containsBean("singerAlias1"));
    System.out.println("Is singer Bean(alias 2) present ? " + beanFactory.containsBean("singerAlias2"));
    final IPerformer singer1 = (IPerformer) beanFactory.getBean("singerAlias1");
    final IPerformer singer2 = (IPerformer) beanFactory.getBean("singerAlias2");
    System.out.println("singer1.equals(singer2) ? " + singer1.equals(singer2));
}
The output would indicate that the two aliases refer to the same bean.
Is singer Bean(alias 1) present ? true
Is singer Bean(alias 2) present ? true
Creating a singer instance com.performer.Singer@13f3045
singer1.equals(singer2) ? true
It is possible to get all aliases for a bean
System.out.println("Displaying all aliases : ");
String[] aliases = beanFactory.getAliases("singerAlias1");
for (String alias : aliases) {
    System.out.println(alias);
}
The output would display the aliases:
Displaying all aliases : 
singer
singerAlias2
The parameter to the above method could also be the bean id.
All Identifiers MUST BE UNIQUE
If the bean definitions in the xml configuration were uncommented then it would result in the following error:
Exception in thread "main" org.springframework.beans.factory.parsing.
BeanDefinitionParsingException: Configuration problem: Bean name 'noName' 
is already used in this file Offending resource: class path resource  
[bean-identifier.xml]
No identifier be it name or id, can repeat in the context of a bean factory.
Also while a bean can have
, it cannot have multiple id attribute.

3 comments:

  1. Great post! Was looking for a simple straightforward explanation and found it! Thanks for posting this :)

    ReplyDelete
    Replies
    1. Nice post!!! Simple yet more clear with examples... Thanks for clearing the doubts :)

      Delete