Showing posts with label spring-api. Show all posts
Showing posts with label spring-api. Show all posts

Saturday, 19 March 2011

Spring : ServiceLocatorFactoryBean Interface

This interface is used for lazy initialization of beans:

The problem with ApplicationContextAware and ObjectFactory is the component is coupled with the spring API.

Steps required

Step 1

Now to achieve 100% abstraction, we need some way by which Spring can dynamically create the instance of another bean and return it to us. So this is what we do as our first step:

//the interface implemented by various impl classes
public interface BillPaymentService {

}
//step 1
public interface BillPaymentServiceFactory {

public BillPaymentService getService();
}


Step 2


public interface CustomerService{ 
void payBill(double amt)
}
public class CustomerServiceImpl3 implements CustomerService {

private BillPaymentServiceFactory billPaymentServiceFactory;

public void setBillPaymentServiceFactory(
BillPaymentServiceFactory billPaymentServiceFactory) {
this.billPaymentServiceFactory = billPaymentServiceFactory;
}

public void payBill(double amt) {
BillPaymentService billService = billPaymentServiceFactory.getService();
//we need to call some method of BillPaymentService here. Right now not required.
}


Step 3 :  Xml config

<!-- We are using the ServiceLocatorFactoryBean here -->
<!-- In the bean just refer to serviceLocator -->
bean id="customerService3" class="com.xxxxx.CustomerServiceImpl3">
<property name="billPaymentServiceFactory" ref="serviceLocator"/>
/bean>

<bean id="serviceLocator"
class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
<property name="serviceLocatorInterface" value="com.xxxxx.BillPaymentServiceFactory"/>
/bean>

We are injecting the ServiceLocator in CustomerService bean which implement factory interface for us and provide an instance of the target bean transparently.

Spring : ObjectFactory Interface

This approach helps us to deal with "lazy initialization" of bean. The problem with ApplicationContextAware approach was that we need to know the id of the bean. No doubt we can inject the id of the bean somehow, but that still means more code.

This interface is even used manually by Spring framework to create bean objects.

Example:

public interface CustomerService {

public void payBill(double amt);
}
public class CustomerServiceImpl2 implements CustomerService {

private ObjectFactory<BillPaymentService> factory;

public void setFactory(ObjectFactory<BillPaymentService> factory) {
this.factory = factory;
}

public void payBill(double amt) {
BillPaymentService billService = factory.getObject();
//we need to call some method of BillPaymentService here. Right now not required.
}
}

Now in the bean descriptor file we have to use idref tag :

<!--  We are using ObjectFactory interface here -->    
<bean id="customerService2" class="com.xxxxx.CustomerServiceImpl2">
<property name="factory">
<bean
class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName">
<idref local="billPaymentService" />
</property>
</bean>
</property>
</bean>

<!-- idref is referring to the local bean billPaymetService defined here -->
<bean id="billPaymentService" class="ex6.BillPaymentServiceImpl" scope="prototype" />



Spring : ApplicationContextAware Interface

Suppose you have some java classes which are unable (or you don’t want it) to be wired to the Spring application context; for example, an auto generated web service client class! But you do want to use the dependency injection feature of Spring to get some of the other beans injected in to this class. How can we make this happen? One way to achieve this would be to use the ApplicationContextAware interface provided by Spring.
As we know, beans are loaded from ApplicationContext instance. So by implementing the callback interface, any bean can access the context and communicate with other beans directly.
Create a class named ApplicationContext which implements  ApplicationContextAware. The inherited method, ‘setApplicationContext(…)’ will get called during the creation of this bean, providing the reference to the context. Our program should store this for a later interaction with the context.
Example:
public interface CustomerService {

public void payBill(double amt);
}
public class CustomerServiceImpl implements CustomerService, ApplicationContextAware {

private ApplicationContext ctx;

@Override
public void setApplicationContext(ApplicationContext ctx) {
this.ctx = ctx;
}

private BillPaymentService createBillPaymentInstance() {
return ctx.getBean("billPaymentService", BillPaymentService.class);
}

public void payBill(double amt) {
//now get the bean and do whatever you want for that context
BillPaymentService billingService = createBillPaymentInstance();
//we need to call some method of BillPaymentService here. Right now not required.
}
}

Spring : Creating custom factory-bean

Because of the complexity involved, we tend to write our own factory classes to initialize complex beans. There are couple of ways :

  • Traditional way of writing factory classes
  • Using FactoryBean Api for writing a factory class

example :

Suppose we have a bean called MyService. Likewise there can be many other beans, and there is a factory class to which contain multiple methods to return these different type of beans. So based on the parameter of the function, it generates a bean of different type.

Consider the bean class:

package ex3;

public class MyService {

//some bean components
}


Consider the factory class :


import javax.sql.DataSource;

public class MyServiceLocator {

public MyService createMyService() {
//we assume there is some complex code to initialize MyService bean
return new MyService();
}

public MyService createMyService(DataSource dataSource) {
//some database specific code to fetch values required for instantiating the bean
return new MyService();
}
}


Describing the factory class:


<!-- define the bean of type factory-class -->
<bean id="serviceLocator" class="ex3.MyServiceLocator" />
<!-- Now get the bean created by factory class by factory-bean -->
<bean id="myService" factory-bean="serviceLocator" factory-method="createMyService" />


Creating the beans from factory class:


import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyServiceLocatorTest {

public void testMyServiceLocator() {
ApplicationContext container = new ClassPathXmlApplicationContext("/sompath/config.xml");
//getbean of type myservice from factory class inside containter
MyService myService = container.getBean("myService", MyService.class);
}


Now this will call factory-method of type with no arguments, but when factory-method has argument then we can do this by these 2 methods. See here.