Service Locator Factory Pattern

Vibhor Pareek
Javarevisited
Published in
3 min readJan 10, 2023

Introduction

Service Locator Factory pattern helps you to locate services at runtime based on certain criteria. In this article, I will be mainly focusing on spring provided service locator pattern & its implementation. There are many ways to implement service locator pattern but spring service locator pattern helps you to avoid boiler plate code & implement it efficiently & quickly.

From Martin Fowler’s article talking about locator pattern :
“The basic idea behind a service locator is to have an object that knows how to get hold of all of the services that an application might need. So a service locator for this application would have a method that returns a ‘service’ when one is needed.”

Problem Statement

Let’s take a simple example of a payment system where you have different payment processors like Visa/Amex/MasterCard. These payment processors have different methods to pay. We need to build a controller that calls the appropriate method based on type provided by client. Let’s try to understand & build a very basic code structure around it. Before that, we will take a look at the components involved in locator pattern.

Components

  • Client: Consumer that requires the service at runtime.
  • Service Locator: Service locator is responsible for returning the service on-demand to the client. It abstracts the lookup or creation of the service.
  • Initial Context: It creates, registers and caches the service. This is the starting point of the lookup and creation.
  • Service Factory: The service factory provides lifecycle management for the service with support to create, lookup, or remove a service.
  • Service: Concrete implementation of the service desired by the client.

Implementation

  1. Let’s start with building the generic interface for our payment processor as below :
public interface PaymentProcessor {
public void pay();
}

2. Concrete implementation of interface PaymentProcessor with Visa. In the below class, we have specified the name as “Visa” for the component.

@Slf4j
@Component("Visa")
public class VisaPaymentProcessor implements PaymentProcessor{



@Override
public void pay() {
log.info("Paying through Visa Network!");
}
}

3. Concrete implementation of interface PaymentProcessor with Amex. In the below class, we have specified the name as “Amex” for the component.

@Slf4j
@Component("Amex")
public class AmexPaymentProcessor implements PaymentProcessor{


@Override
public void pay() {
log.info("Paying through Amex Network!");
}
}

4. Now let’s write service locator interface. It has a method which takes a type as input param & returns a PaymentProcessor type as below :

public interface PaymentRegistry {

public PaymentProcessor findProcessor(String type);

}

5. Using the above service locator interface, I will now add it to the spring factory bean config to use this as service locator interface.

@Configuration
public class ServiceLocatorConfig {

@Bean("paymentRegistry")
public FactoryBean<?> getBean() {
ServiceLocatorFactoryBean bean = new ServiceLocatorFactoryBean();
bean.setServiceLocatorInterface(PaymentRegistry.class);
return bean;
}

}

6. Sample controller to test our changes

@RestController
@RequestMapping("/payment-service")
@Slf4j
public class TestController {

@Autowired
private PaymentRegistry paymentRegistry;


@GetMapping("/v1/pay")
public void payViaProcessor(@RequestParam String type) {
log.info("Paying thru type : {} ", type );
paymentRegistry.findProcessor(type).pay();
}
}

Output

http://localhost:8080/payment-service/v1/pay?type=Visa
Image Visa Type
http://localhost:8080/payment-service/v1/pay?type=Amex
Image Amex Type

Take Aways

  • The pattern helps you to remove tight coupling making it complaint to Open Closed Principle.
  • Removal of boiler plate code to build caches & factory of services since spring takes care of it for you :)

Happy Learning! ;)

--

--