Friday, December 25, 2020

ServiceLocatorFactoryBean in Spring Framework

ServiceLocatorFactoryBean in Spring framework as the name suggests is an implementation of service locator design pattern and helps with locating the service at run time.

ServiceLocatorFactoryBean helps if you have more than one implementation of the same type and want to use the appropriate implementation at the run time i.e. you have an interface and more than one class implementing that interface and you want to have a factory that will return an appropriate object at run time.

How ServiceLocatorFactoryBean works

ServiceLocatorFactoryBean class in Spring has a field serviceLocatorInterface that takes an interface which must have one or more methods with the signatures MyService getService() or MyService getService(String id)). Spring framework creates a dynamic proxy which implements that interface, delegating to an underlying BeanFactory.

When you call getService(String id)) method of your interface passing the bean id as an argument, internally through the proxy BeanFactory.getBean(String id) is called, returning the bean whose name is passed as an argument to the getBean() method of the BeanFactory.

Advantage of having a ServiceLocatorFactoryBean is that such service locators permit the decoupling of calling code from the BeanFactory API, by using an appropriate custom locator interface. They will typically be used for prototype beans, i.e. for factory methods that are supposed to return a new instance for each call.

Spring ServiceLocatorFactoryBean Example

Let’s see an example to make things clearer as the theory looks quite complex!

We want to determine at the run time whether to make a cash payment or card payment based on the input (argument passed). So we have an interface IPayment and implementing classes CashPayment and CardPayment.

public interface IPayment{
 void executePayment();
}

public class CashPayment implements IPayment{ 
 public void executePayment() {
  System.out.println("Perform Cash Payment "); 
 }
}

public class CardPayment implements IPayment{
 public void executePayment() {
  System.out.println("Perform Card Payment "); 
 }
}

Service locator interface

This service locator interface will be injected in ServiceLocatorFactoryBean.
public interface PaymentFactory {
 public IPayment getPayment(String paymentType);
}

Here is the bean where ServiceLocatorFactoryBean will be injected, it also has a method where the injected factory bean instance is used to get the required bean by bean name.

import org.springframework.beans.factory.annotation.Autowired;

public class PaymentService {
 @Autowired
 private PaymentFactory paymentFactory;

 public void setPaymentFactory(PaymentFactory paymentFactory) {
  this.paymentFactory = paymentFactory;
 }
 
 public void makePayment(String paymentType){
  IPayment payment = paymentFactory.getPayment(paymentType);
  payment.executePayment();
 }
}

XML Configuration

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    
  <context:annotation-config/> 
  
   <!-- Prototype bean since we have state -->
  <bean id="cashPayment" class="org.netjs.exp.Spring_Example.CashPayment" 
   scope="prototype" />
  <bean id="cardPayment" class="org.netjs.exp.Spring_Example.CardPayment" 
   scope="prototype" />
  
  <!-- ServiceLocatorFactoryBean -->
  <bean id="paymentFactory" 
    class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
    <property name="serviceLocatorInterface" value="org.netjs.exp.Spring_Example.PaymentFactory"/>
  </bean>
 
  <bean id="payServiceBean" class="org.netjs.exp.Spring_Example.PaymentService">
  </bean>
</beans>
You can run the example using the following code.
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
  public static void main( String[] args ){
    AbstractApplicationContext context = new ClassPathXmlApplicationContext
    ("appcontext.xml");
    PaymentService payService = (PaymentService)context.getBean("payServiceBean");
    payService.makePayment("cardPayment");

    context.registerShutdownHook();   
  } 
}

Note that "cardPayment" is passed here as the payment type. From the service factory dynamic proxy implementation Spring framework will internally call BeanFactory.getBean(“cardPayment”) to return an instance of the specified bean.

Reference: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/config/ServiceLocatorFactoryBean.html

That's all for this topic ServiceLocatorFactoryBean in Spring. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Bean Scopes in Spring With Examples
  2. ApplicationContextAware And BeanNameAware Interfaces in Spring Framework
  3. Lazy Initialization in Spring Using lazy-init And @Lazy Annotation
  4. Bean Definition Inheritance in Spring
  5. Sending Email Using Spring Framework Example

You may also like-

  1. How to Read Properties File in Spring Framework
  2. Circular Dependency in Spring Framework
  3. Spring NamedParameterJdbcTemplate Select Query Example
  4. super Keyword in Java With Examples
  5. Difference Between HashMap And ConcurrentHashMap in Java
  6. ConcurrentSkipListSet in Java With Examples
  7. Serialization Proxy Pattern in Java
  8. Optional Class in Java With Examples

No comments:

Post a Comment