서비스 로케이터 패턴


서비스 로케이터 패턴은 JNDI를 사용하여 다양한 서비스를 쿼리하고 찾을 때 사용됩니다. 서비스에 대한 JNDI를 찾는 데 비용이 많이 든다는 점을 고려하여 서비스 로케이터 패턴은 캐싱 기술을 활용합니다. 서비스가 처음 요청되면 서비스 로케이터는 JNDI에서 서비스를 조회하고 서비스 객체를 캐시합니다. 동일한 서비스가 다시 요청되면 서비스 로케이터는 해당 캐시를 검색하므로 애플리케이션 성능이 크게 향상될 수 있습니다. 다음은 이 디자인 패턴의 엔터티입니다.

  • Service - 실제로 요청을 처리하는 서비스입니다. 이 서비스에 대한 참조는 JNDI 서버에서 찾을 수 있습니다.

  • Context / 초기 컨텍스트 - 찾을 서비스에 대한 참조가 포함된 JNDI 컨텍스트입니다.

  • 서비스 로케이터 - 서비스 로케이터는 JNDI 조회 및 캐싱 서비스를 통해 서비스를 받기 위한 단일 연락 창구입니다.

  • Cache - 캐시는 서비스에 대한 참조를 재사용할 수 있도록 저장합니다.

  • Client - 클라이언트는 ServiceLocator를 통해 서비스를 호출하는 개체입니다.

Implementation

엔티티를 나타내는 다양한 객체로 ServiceLocator, InitialContext, Cache, Service을 생성하겠습니다. Service1Service2는 엔터티 서비스를 나타냅니다.

ServiceLocatorPatternDemo, 데모 클래스는 ServiceLocator를 사용하여 서비스 로케이터 디자인 패턴을 시연하는 클라이언트로 제공됩니다.

servicelocator_pattern_uml_diagram.jpg

1단계

서비스 인터페이스 서비스를 생성합니다.

Service.java

public interface Service {
   public String getName();
   public void execute();
}

2단계

엔티티 서비스를 생성합니다.

Service1.java

public class Service1 implements Service {
   public void execute(){
      System.out.println("Executing Service1");
   }

   @Override
   public String getName() {
      return "Service1";
   }
}

Service2.java

public class Service2 implements Service {
   public void execute(){
      System.out.println("Executing Service2");
   }

   @Override
   public String getName() {
      return "Service2";
   }
}

3단계

JNDI 쿼리에 대한 초기 컨텍스트를 생성합니다.

InitialContext.java

public class InitialContext {
   public Object lookup(String jndiName){
      if(jndiName.equalsIgnoreCase("SERVICE1")){
         System.out.println("Looking up and creating a new Service1 object");
         return new Service1();
      }else if (jndiName.equalsIgnoreCase("SERVICE2")){
         System.out.println("Looking up and creating a new Service2 object");
         return new Service2();
      }
      return null;		
   }
}

4단계

캐시를 생성합니다.

Cache.java

import java.util.ArrayList;
import java.util.List;

public class Cache {

   private List<Service> services;

   public Cache(){
      services = new ArrayList<Service>();
   }

   public Service getService(String serviceName){
      for (Service service : services) {
         if(service.getName().equalsIgnoreCase(serviceName)){
            System.out.println("Returning cached  "+serviceName+" object");
            return service;
         }
      }
      return null;
   }

   public void addService(Service newService){
      boolean exists = false;
      for (Service service : services) {
         if(service.getName().equalsIgnoreCase(newService.getName())){
            exists = true;
         }
      }
      if(!exists){
         services.add(newService);
      }
   }
}

5단계

서비스 로케이터를 생성합니다.

ServiceLocator.java

public class ServiceLocator {
   private static Cache cache;

   static {
      cache = new Cache();		
   }

   public static Service getService(String jndiName){

      Service service = cache.getService(jndiName);

      if(service != null){
         return service;
      }

      InitialContext context = new InitialContext();
      Service service1 = (Service)context.lookup(jndiName);
      cache.addService(service1);
      return service1;
   }
}

6단계

ServiceLocator를 사용하여 서비스 로케이터 디자인 패턴을 시연합니다.

ServiceLocatorPatternDemo.java

public class ServiceLocatorPatternDemo {
   public static void main(String[] args) {
      Service service = ServiceLocator.getService("Service1");
      service.execute();
      service = ServiceLocator.getService("Service2");
      service.execute();
      service = ServiceLocator.getService("Service1");
      service.execute();
      service = ServiceLocator.getService("Service2");
      service.execute();		
   }
}

7단계

출력을 확인합니다.

rreee