Service Locator

Este artigo estará abordando um dos catalogados para a arquitetura J2EE, o Service Locator. O nome deste catálogo chama-se Core J2EE Patterns (Core J2EE Patterns)

Service Locator
por Giovani Salvador

São inúmeros os design patterns existentes e especificamente para a arquitetura J2EE temos alguns bons patterns que ajudam a simplificar a codificação.
Neste artigo estarei abordando um dos catalogados para a arquitetura J2EE, o Service Locator. O nome deste catálogo chama-se Core J2EE Patterns (
Core J2EE Patterns)

O problema:

Clientes de serviço EJB precisam localizar o serviço (através de chamadas lookup) utilizando algumas formas padrão da arquitetura de EJB. Estas formas envolvem a localização do objeto que implementa a interface Home do EJB, a solicitação de uma nova instância de um EJB e a chamada aos métodos de negócio. Além destes passos, se vários clientes tem este mesmos trechos de código, existe a duplicidade desta codificação, dificultando a manutenção.
Um outro problema é que se múltiplos clientes solicitam o mesmo objeto Home a performance da aplicação pode degradar uma vez que muitos recursos são consumidos na localização de um EJB.

Exemplo de uma chamada de um cliente de um EJB sem utilizar o ServiceLocator: 
 

    /* A linha abaixo inicializa um contexto para começar a fazer operações de naming.
     *parâmetros adicionais podem ser passados ao initialcontext contendo informações do ambiente.
     */
    Context ctx = new InitialContext();
  
    //a linha de código abaixo retorna um objeto que contém uma referência local ao EJB
    Object ref = ctx.lookup("SessionFacade");
    
    //Transforma a referência local do objeto ref para o tipo do EJB
    SessionFacadeHome sessionFacadeHome = 
      (SessionFacadeHome)PortableRemoteObject.narrow(ref, SessionFacade);
  
    //alinha abaixo cria uma instância de um Session Bean de fachada
    SessionFacade sessionFacade = sessionFacadeHome.create();

 

Os passos acima geralmente estão distribuídos em vários clientes de EJB resultando nos problemas especificados anteriormente. A Solução:

Use um ServiceLocator para abstrair todos estes passos de chamadas a serviço de EJB.
Os passos para localização dos serviços EJB ficam dentro da classe ServiceLocator e os clientes apenas interagem com esta classe.
O cliente passaria a ter esta chamada: 
 

package br.com.portaljava.tutoriais.ejb;

public class TestServiceLocator {

  public static void main( String[]args ) {
    ServiceLocator serviceLocator = ServiceLocator.getInstance();
    try {
      SessionFacadeHome sessionFacadeHome =
        (SessionFacadeHome) serviceLocator.getHome(SessionFacadeHome);
      SessionFacade sessionFacade = sessionFacadeHome.create();
      sessionFacade.inclui(...);
    }catch(ServiceException ex ) {
      System.out.println( ex.getMessage( ));
    }
  }
}

 Código da classe ServiceLocator (Observe que esta classe também implementa o pattern Singleton):

 

package br.com.portaljava.tutoriais.ejb;

import javax.ejb.*;
import javax.naming.*;
import java.util.*;
import javax.rmi.PortableRemoteObject;

/**
 * Implementação de exemplo do Design Pattern Service Locator. Esta classe
 * implementa um cache de interfaces home.
 
 @author Giovani Salvador
 *  
 */
public class ServiceLocator {

  /**
   * Contexto JNDI cuja instaciação será reduzida, já que o custo deste tipo
   * de operação é alto.
   */
  private InitialContext jndiContext;

  /**
   * Este ServiceLocator será um Singleton
   */
  private static ServiceLocator instance;

  /**
   * Cosntrutor privado, evitando multiplas instâncias deste objeto(Singleton).
   *
   */
  private ServiceLocator() {
    try {
      jndiContext = new InitialContext();
    catch (Exception exc) {
      exc.printStackTrace();
    }
  }

  /**
   * Recupera a instancia do Singleton
   */
  public static ServiceLocator getInstance() {
    if (instance == null) {
      instance = new ServiceLocator();
    }
    return instance;
  }

  /**
   * Recupera uma implementação da interface home. O lookup do bean é sempre
   * feito pois é remoto.
   */
  public EJBHome getHome(String jndiName) {
    Object ref = null;
    try {
      ref = jndiContext.lookup(jndiName);
      EJBHome home = (EJBHome) PortableRemoteObject.narrow(ref,
          EJBHome.class);
    catch (Exception exc) {
      exc.printStackTrace();
    }
    return (EJBHome) ref;
  }

  /**
   * Recupera uma implementação da interface Local home. O lookup do bean só é
   * feito se não houver nenhuma referência sua no cache daEJBHomeFactory
   */
  public EJBLocalHome getLocalHome(String jndiName) {
    EJBLocalHome localHome = null;
    try {
      localHome = (EJBLocalHome) EJBHomeFactory.getInstance().lookup(
          jndiName);
    catch (Exception exc) {
      exc.printStackTrace();
    }
    return localHome;
  }
}


Preste atenção a dois métodos na classe ServiceLocator: O getHome e getLocalHome.
O getHome retorna uma referência a uma home de um ejb remoto ao passo que o getLocalHome retorna uma referência a uma home local. Além disso, o método getLocalHome está usando outro pattern para manter o cache de referências a home´s locais, o design pattern EJBHomeFactory, do livro EJB Design Patterns de Floyd Marinescu.
Porque não mantemos cache de referências a home´s remotas também? Bem, em um ambiente distribuído isto pode não ser uma boa prática pois um componente pode estar atendendo em uma máquina e de repente pode atender de outra máquina caso a primeira tenha caído. Daí a referência remota não existe mais. Entraremos em detalhes deste pattern em outro artigo.
É importante observar novamente que o design pattern Service Locator, além de diminiuir a complexidade do código cliente, poupa recursos do lado servidor, aumentando a performance da aplicação. 

Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados