Monday, January 6, 2014

@Configuration vs xml with prototypes

@Configuration vs xml with prototypes


There are two sides to using spring. One is the injection side, and the annotations are  @Autowire, @Inject, @Resource (see http://javaandroidandrest.blogspot.co.il/2013/05/spring-bean-overriding-between-projects.html). The other side is the definition of beans: @Component, @Repository, @Server.

The beginning of spring all injections were done via xml configuration files. With each version spring added more and more annotations so simplify matters.  When it came to injection annotations were usually used and xml files were used only when the annotation was not enough (like using maps).
For configuration files xml were the main default especially when complex configurations were including. One of the more complicated configurations is the prototype.

Prototypes

Before we go into the @Configuration, I would like to add a word on prototypes. In spring there are two scopes one is singleton and the other prototype. Singleton means that only one instance of that bean will exist in the spring context. While prototype means that multiple beans can exist. If you have a multiple singletons (from different types) that reference a prototype bean, each singleton will get its own instance of the prototype.
For example:
@Component
@Scope("prototype")
public class Chair {

}

@Component
public class Garage {

       @Autowired
       Chair chair;
}

@Component
public class House {

       @Autowired
       Chair chair;

}

Anyone that references the house of the garage will get the same instance as everyone else.  Though in the case of the chair both the garage and the house, will each have a separate instance of the chair.
Now when you need to generate during a runtime of the application another instance of the prototype then you need a lookup method.
For example let’s say that during runtime I need to create a new chair, so on my house class I will have a method of: protected Chair createChair();
We cannot create the chair with new Chair(), since then spring will not generate the class, and any injections within the chair class will not happen. So the spring solution to this is to create a lookup method. In the xml you write:
<bean id="house" class="com.domain.House"
       <lookup-method name="createChair" bean="com.domain.Chair" />
</bean>
And in the class you need to add the abstract method
@Component
abstract public class House {

       @Autowired
       Chair chair;

       abstract protected Chair createChair();
}

Spring will then implement this method and any time you call the createChair() a spring instance of the Chair will all injections will be created.

@ Configuration

With spring 3, spring add the @Configuration annotation. What this annotation allows you to do is to actually write all your xml in java code.
So for creating a bean of House we can either add @Component on the house class, we can add to the xml:
<bean id="house" class="com.domain.House"
      
</bean>
Or we can create a class with the annotation of @Configuration to create the bean:
@Configuration
public class ClassFactory {

       @Bean
       public House createHouse(){
              return new House();
       }
}

So for those people that prefer to write java code over xml files, you can now use configuration classes.
You client code still stays the same and you just inject the House using @Autowired.
Of course since the house is a singleton the method of “createHouse” will be called by spring only once and all places that inject the house will get this instance. In the case of prototypes you will add the method of:
       @Bean
       @Scope("prototype")
       public Chair createChair(){
              return new Chair();
       }

Now anytime that you inject a chair to a bean a new instance of the chair will be instantiated.
The configuration class allows you to set any properties that you want on the bean and write any code that you need. The spring framework will do its magic once the runtime finishes the method with the @Bean annotation. For example the method of “afterPropertiesSet” will be called once the @Bean method finishes.
A added advantage to the configuration bean is now you have a built in lookup method for creating prototype beans. Any class that has the @Configuration annotation is also a spring bean, so you can now inject this bean in your class and call the “createChair”. So you can now write in your house class:
@Component
public class House {

       @Autowired
       Chair chair;
      
       @Autowired
       ClassFactory factory;
      
       public Chair createChair(){
              return factory.createChair();
       }

}




No comments:

Post a Comment