Core J2EE Patterns - Service Locator--oracle官网

原文地址:http://www.oracle.com/technetwork/java/servicelocator-137181.html

Context

Service lookup and creation involves complex interfaces and network operations.

Problem

J2EE clients interact with service components, such as Enterprise JavaBeans (EJB) and Java Message Service (JMS) components, which provide business services and persistence capabilities. To interact with these components, clients must either locate the service component (referred to as a lookup operation) or create a new component. For instance, an EJB client must locate the enterprise bean‘s home object, which the client then uses either to find an object or to create or remove one or more enterprise beans. Similarly, a JMS client must first locate the JMS Connection Factory to obtain a JMS Connection or a JMS Session.

All Java 2 Platform, Enterprise Edition (J2EE) application clients use the JNDI common facility to look up and create EJB and JMS components. The JNDI API enables clients to obtain an initial context object that holds the component name to object bindings. The client begins by obtaining the initial context for a bean‘s home object. The initial context remains valid while the client session is valid. The client provides the JNDI registered name for the required object to obtain a reference to an administered object. In the context of an EJB application, a typical administered object is an enterprise bean‘s home object. For JMS applications, the administered object can be a JMS Connection Factory (for a Topic or a Queue) or a JMS Destination (a Topic or a Queue).

So, locating a JNDI-administered service object is common to all clients that need to access that service object. That being the case, it is easy to see that many types of clients repeatedly use the JNDI service, and the JNDI code appears multiple times across these clients. This results in an unnecessary duplication of code in the clients that need to look up services.

Also, creating a JNDI initial context object and performing a lookup on an EJB home object utilizes significant resources. If multiple clients repeatedly require the same bean home object, such duplicate effort can negatively impact application performance.

Let us examine the lookup and creation process for various J2EE components.

  1. The lookup and creation of enterprise beans relies upon the following:

    • A correct setup of the JNDI environment so that it connects to the naming and directory service used by the application. Setup entails providing the location of the naming service and the necessary authentication credentials to access that service.
    • The JNDI service can then provide the client with an initial context that acts as a placeholder for the component name-to-object bindings. The client requests this initial context to look up the EJBHome object for the required enterprise bean by providing the JNDI name for that EJBHome object.
    • Find the EJBHome object using the initial context‘s lookup mechanism.
    • After obtaining the EJBHome object, create, remove, or find the enterprise bean, using the EJBHome object‘s create, move, and find (for entity beans only).
  2. The lookup and creation of JMS components (Topic, Queue, QueueConnection, QueueSession, TopicConnection, TopicSession, and so forth) involves the following steps. Note that in these steps, Topic refers to the publish/subscribe messaging model and Queue refers to the point-to-point messaging model.
    • Set up the JNDI environment to the naming service used by the application. Setup entails providing the location of the naming service and the necessary authentication credentials to access that service.
    • Obtain the initial context for the JMS service provider from the JNDI naming service.
    • Use the initial context to obtain a Topic or a Queue by supplying the JNDI name for the topic or the queue. Topic and Queue are JMSDestination objects.
    • Use the initial context to obtain a TopicConnectionFactory or a QueueConnectionFactory by supplying the JNDI name for the topic or queue connection factory.
    • Use the TopicConnectionFactory to obtain a TopicConnection or QueueConnectionFactory to obtain a QueueConnection.
    • Use the TopicConnection to obtain a TopicSession or a QueueConnection to obtain a QueueSession.
    • Use the TopicSession to obtain a TopicSubscriber or a TopicPublisher for the required Topic. Use the QueueSession to obtain a QueueReceiver or a QueueSender for the required Queue.

The process to look up and create components involves a vendor-supplied context factory implementation. This introduces vendor dependency in the application clients that need to use the JNDI lookup facility to locate the enterprise beans and JMS components, such as topics, queues, and connection factory objects.

Forces

  • EJB clients need to use the JNDI API to look up EJBHome objects by using the enterprise bean‘s registered JNDI name.
  • JMS clients need to use JNDI API to look up JMS components by using the JNDI names registered for JMS components, such as connection factories, queues, and topics.
  • The context factory to use for the initial JNDI context creation is provided by the service provider vendor and is therefore vendor- dependent. The context factory is also dependent on the type of object being looked up. The context for JMS is different from the context for EJB, with different providers.
  • Lookup and creation of service components could be complex and may be used repeatedly in multiple clients in the application.
  • Initial context creation and service object lookups, if frequently required, can be resource-intensive and may impact application performance. This is especially true if the clients and the services are located in different tiers.
  • EJB clients may need to reestablish connection to a previously accessed enterprise bean instance, having only its Handle object.

Solution

Use a Service Locator object to abstract all JNDI usage and to hide the complexities of initial context creation, EJB home object lookup, and EJB object re-creation. Multiple clients can reuse the Service Locator object to reduce code complexity, provide a single point of control, and improve performance by providing a caching facility.

This pattern reduces the client complexity that results from the client‘s dependency on and need to perform lookup and creation processes, which are resource-intensive. To eliminate these problems, this pattern provides a mechanism to abstract all dependencies and network details into the Service Locator.

Structure

Figure 8.31 shows the class diagram representing the relationships for the Service Locator pattern.

 
Figure 8.31 Service Locator class diagram

Participants and Responsibilities

Figure 8.32 contains the sequence diagram that shows the interaction between the various participants of the Service Locator pattern.


Figure 8.32 Service Locator Sequence diagram

Client

This is the client of the Service Locator. The client is an object that typically requires access to business objects such as a Business Delegate (see "Business Delegate" on page 248).

Service Locator

The Service Locator abstracts the API lookup (naming) services, vendor dependencies, lookup complexities, and business object creation, and provides a simple interface to clients. This reduces the client‘s complexity. In addition, the same client or other clients can reuse the Service Locator.

InitialContext

The InitialContext object is the start point in the lookup and creation process. Service providers provide the context object, which varies depending on the type of business object provided by the Service Locator‘s lookup and creation service. A Service Locator that provides services for multiple types of business objects (such as enterprise beans, JMS components, and so forth) utilizes multiple types of context objects, each obtained from a different provider (e.g., context provider for an EJB application server may be different from the context provider for JMS service).

ServiceFactory

The ServiceFactory object represents an object that provides life cycle management for the BusinessService objects. The ServiceFactory object for enterprise beans is an EJBHome object. The ServiceFactory for JMS components can be a JMS ConnectionFactory object, such as a TopicConnectionFactory (for publish/subscribe messaging model) or a QueueConnectionFactory (for point-to-point messaging model).

BusinessService

The BusinessService is a role that is fulfilled by the service the client is seeking to access. The BusinessService object is created or looked up or removed by the ServiceFactory. The BusinessService object in the context of an EJB application is an enterprise bean. The BusinessService object in the context of a JMS application can be a TopicConnection or a QueueConnection. The TopicConnection and QueueConnection can then be used to produce a JMSSession object, such as TopicSession or a QueueSession respectively.

Strategies

EJB Service Locator Strategy

The Service Locator for enterprise bean components uses EJBHome object, shown as BusinessHome in the role of the ServiceFactory. Once the EJBHome object is obtained, it can be cached in the ServiceLocator for future use to avoid another JNDI lookup when the client needs the home object again. Depending on the implementation, the home object can be returned to the client, which can then use it to look up, create, and remove enterprise beans. Otherwise, the ServiceLocator can retain (cache) the home object and gain the additional responsibility of proxying all client calls to the home object. The class diagram for the EJB Service Locator strategy is shown in Figure 8.33.

 
Figure 8.33 EJB Service Locator Strategy class diagram

The interaction between the participants in a Service Locator for an enterprise bean is shown in Figure 8.34.


Figure 8.34 EJB Service Locator Strategy sequence diagram

JMS Queue Service Locator Strategy

This strategy is applicable to point-to-point messaging requirements. The Service Locator for JMS components uses QueueConnectionFactory objects in the role of the ServiceFactory. The QueueConnectionFactory is looked up using its JNDI name. The QueueConnectionFactory can be cached by the ServiceLocator for future use. This avoids repeated JNDI calls to look it up when the client needs it again. The ServiceLocator may otherwise hand over the QueueConnectionFactory to the client. The Client can then use it to create a QueueConnection. A QueueConnection is necessary in order to obtain a QueueSession or to create a Message, a QueueSender (to send messages to the queue), or a QueueReceiver (to receive messages from a queue). The class diagram for the JMS Queue Service Locator strategy is shown in Figure 8.35. In this diagram, the Queue is a JMS Destination object registered as a JNDI-administered object representing the queue. The Queue object can be directly obtained from the context by looking it up using its JNDI name.

 
Figure 8.35 JMS Queue Service Locator strategy class diagram

The interaction between the participants in a Service Locator for point-to-point messaging using JMS Queues is shown in Figure 8.36.


Figure 8.36 JMS Queue Service Locator Strategy sequence diagram

JMS Topic Service Locator Strategy

This strategy is applicable to publish/subscribe messaging requirements. The Service Locator for JMS components uses TopicConnectionFactory objects in the role of the ServiceFactory. The TopicConnectionFactory is looked up using its JNDI name. The TopicConnectionFactory can be cached by the ServiceLocator for future use. This avoids repeated JNDI calls to look it up when the client needs it again. The ServiceLocator may otherwise hand over the TopicConnectionFactory to the client. The Client can then use it to create a TopicConnection. A TopicConnection is necessary in order to obtain a TopicSession or to create a Message, a TopicPublisher (to publish messages to a topic), or a TopicSubscriber (to subscribe to a topic). The class diagram for the JMS Topic Service Locator strategy is shown in Figure 8.37. In this diagram, the Topic is a JMS Destination object registered as a JNDI-administered object representing the topic. The Topic object can be directly obtained from the context by looking it up using its JNDI name.

 
Figure 8.37 JMS Topic Service Locator strategy

The interaction between the participants in a Service Locator for publish/subscribe messaging using JMS Topics is shown in Figure 8.38.


Figure 8.38 JMS Topic Service Locator Strategy sequence diagram

Combined EJB and JMS Service Locator Strategy

These strategies for EJB and JMS can be used to provide separate Service Locator implementations, since the clients for EJB and JMS may more likely be mutually exclusive. However, if there is a need to combine these strategies, it is possible to do so to provide the Service Locator for all objects-enterprise beans and JMS components.

Type Checked Service Locator Strategy

The diagrams in Figures 8.37 and 8.38 provide lookup facilities by passing in the service lookup name. For an enterprise bean lookup, the Service Locator needs a class as a parameter to thePortableRemoteObject.narrow() method. The Service Locator can provide a getHome()method, which accepts as arguments the JNDI service name and the EJBHome class object for the enterprise bean. Using this method of passing in JNDI service names and EJBHome class objects can lead to client errors. Another approach is to statically define the services in the ServiceLocator, and instead of passing in string names, the client passes in a constant. Example 8.34 illustrates such a strategy.

This strategy has trade-offs. It reduces the flexibility of lookup, which is in the Services Property Locator strategy, but add the type checking of passing in a constant to theServiceLocator.getHome() method.

Service Locator Properties Strategy

This strategy helps to address the trade-offs of the type checking strategy. This strategy suggests the use of property files and/or deployment descriptors to specify the JNDI names and the EJBHome class name. For presentation-tier clients, such properties can be specified in the presentation-tier deployment descriptors or property files. When the presentation tier accesses the business tier, it typically uses the Business Delegate pattern.

The Business Delegate interacts with the Service Locator to locate business components. If the presentation tier loads the properties on initialization and can provide a service to hand out the JNDI names and the EJB class names for the required enterprise bean, then the Business Delegate could request this service to obtain them. Once the Business Delegate has the JNDI name and the EJBHome Class name, it can request the Service Locator for the EJBHome by passing these properties as arguments.

The Service Locator can in turn use Class.forName(EJBHome ClassName) to obtain the EJBHome Class object and go about its business of looking up the EJBHome and using thePortable RemoteObject.narrow() method to cast the object, as shown by the getHome()method in the ServiceLocator sample code in Example 8.33. The only thing that changes is where the JNDI name and the Class objects are coming from. Thus, this strategy avoids hardcoded JNDI names in the code and provides for flexibility of deployment. However, due to the lack of type checking, there is scope for avoiding errors and mismatches in specifying the JNDI names in different deployment descriptors.

Consequences

  • Abstracts Complexity 
    The Service Locator pattern encapsulates the complexity of this lookup and creation process (described in the problem) and keeps it hidden from the client. The client does not need to deal with the lookup of component factory objects (EJBHome, QueueConnectionFactory, and TopicConnectionFactory, among others) because the ServiceLocator is delegated that responsibility.
  • Provides Uniform Service Access to Clients 
    The Service Locator pattern abstracts all the complexities, as explained previously. In doing so, it provides a very useful and precise interface that all clients can use. The pattern interface ensures that all types of clients in the application uniformly access business objects, in terms of lookup and creation. This uniformity reduces development and maintenance overhead.
  • Facilitates Adding New Business Components 
    Because clients of enterprise beans are not aware of the EJBHome objects, it‘s possible to add new EJBHome objects for enterprise beans developed and deployed at a later time without impacting the clients. JMS clients are not directly aware of the JMS connection factories, so new connection factories can be added without impacting the clients.
  • Improves Network Performance 
    The clients are not involved in JNDI lookup and factory/home object creation. Because the Service Locator performs this work, it can aggregate the network calls required to look up and create business objects.
  • Improves Client Performance by Caching 
    The Service Locator can cache the initial context objects and references to the factory objects (EJBHome, JMS connection factories) to eliminate unnecessary JNDI activity that occurs when obtaining the initial context and the other objects. This improves the application performance.

Sample Code

Implementing Service Locator Pattern

A sample implementation of the Service Locator pattern is shown in Example 8.33. An example for implementing the Type Checked Service Locator strategy is listed in Example 8.34.

Example 8.33 Implementing Service Locator

package corepatterns.apps.psa.util;
import java.util.*;
import javax.naming.*;
import java.rmi.RemoteException;
import javax.ejb.*;
import javax.rmi.PortableRemoteObject;
import java.io.*;

public class ServiceLocator {
  private static ServiceLocator me;
  InitialContext context = null;

  private ServiceLocator()
  throws ServiceLocatorException {
    try {
      context = new InitialContext();
    } catch(NamingException ne) {
      throw new ServiceLocatorException(...);
    }
  }

  // Returns the instance of ServiceLocator class
  public static ServiceLocator getInstance()
  throws ServiceLocatorException {
    if (me == null) {
      me = new ServiceLocator();
    }
    return me;
  }

  // Converts the serialized string into EJBHandle
  // then to EJBObject.
  public EJBObject getService(String id)
  throws ServiceLocatorException {
    if (id == null) {
      throw new ServiceLocatorException(...);
    }
    try {
      byte[] bytes = new String(id).getBytes();
      InputStream io = new
        ByteArrayInputStream(bytes);
      ObjectInputStream os = new
        ObjectInputStream(io);
      javax.ejb.Handle handle =
        (javax.ejb.Handle)os.readObject();
      return handle.getEJBObject();
    } catch(Exception ex) {
      throw new ServiceLocatorException(...);
    }
  }

  // Returns the String that represents the given
  // EJBObject‘s handle in serialized format.
  protected String getId(EJBObject session)
  throws ServiceLocatorException {
    try {
      javax.ejb.Handle handle = session.getHandle();
      ByteArrayOutputStream fo = new
        ByteArrayOutputStream();
      ObjectOutputStream so = new
        ObjectOutputStream(fo);
      so.writeObject(handle);
      so.flush();
      so.close();
      return new String(fo.toByteArray());
    } catch(RemoteException ex) {
      throw new ServiceLocatorException(...);
    } catch(IOException ex) {
      throw new ServiceLocatorException(...);
    }
    return null;
  }

  // Returns the EJBHome object for requested service
  // name. Throws ServiceLocatorException If Any Error
  // occurs in lookup
  public EJBHome getHome(String name, Class clazz)
  throws ServiceLocatorException {
    try {
      Object objref = context.lookup(name);
      EJBHome home = (EJBHome)
        PortableRemoteObject.narrow(objref, clazz);
      return home;
    } catch(NamingException ex) {
      throw new ServiceLocatorException(...);
    }
  }
}

Implementing Type Checked Service Locator Strategy

Example 8.34 Implementing Type Checked Service Locator Strategy

package corepatterns.apps.psa.util;
// imports
...
public class ServiceLocator {
  // singleton‘s private instance
  private static ServiceLocator me;

  static {
    me = new ServiceLocator();
  }

  private ServiceLocator() {}

  // returns the Service Locator instance
  static public ServiceLocator getInstance() {
    return me;
  }

  // Services Constants Inner Class - service objects
  public class Services {
    final public static int PROJECT  = 0;
    final public static int RESOURCE = 1;
  }    

  // Project EJB related constants
  final static Class  PROJECT_CLASS = ProjectHome.class;
  final static String PROJECT_NAME  = "Project";

  // Resource EJB related constants

  final static Class  RESOURCE_CLASS = ResourceHome.class;
  final static String RESOURCE_NAME  = "Resource";

  // Returns the Class for the required service
  static private Class getServiceClass(int service){
    switch( service ) {
      case Services.PROJECT:
        return PROJECT_CLASS;
      case Services.RESOURCE:
      return RESOURCE_CLASS;
    }
    return null;
  }

  // returns the JNDI name for the required service
  static private String getServiceName(int service){
    switch( service ) {
      case Services.PROJECT:
        return PROJECT_NAME;
      case Services.RESOURCE:
        return RESOURCE_NAME;
    }
    return null;
  }

  /* gets the EJBHome for the given service using the
  ** JNDI name and the Class for the EJBHome
  */
  public EJBHome getHome( int s )
    throws ServiceLocatorException {
    EJBHome home = null;
    try {
        Context initial  = new InitialContext();

      // Look up using the service name from
      // defined constant
      Object objref =
        initial.lookup(getServiceName(s));

      // Narrow using the EJBHome Class from
      // defined constant
      Object obj = PortableRemoteObject.narrow(
                objref, getServiceClass(s));
      home = (EJBHome)obj;
    }
    catch( NamingException ex ) {
        throw new ServiceLocatorException(...);
    }
    catch( Exception ex ) {
        throw new ServiceLocatorException(...);
    }
    return home;
  }
}

The client code to use the Service Locator for this strategy may look like the code in Example 8.35.

Example 8.35 Client Code for Using the Service Locator

public class ServiceLocatorTester {
  public static void main( String[] args ) {
    ServiceLocator serviceLocator =
      ServiceLocator.getInstance();
    try {
      ProjectHome projectHome = (ProjectHome)
        serviceLocator.getHome(
          ServiceLocator.Services.PROJECT );
    }
    catch( ServiceException ex ) {
      // client handles exception
      System.out.println( ex.getMessage( ));
    }
  }
}

This strategy is about applying type checking to client lookup. It encapsulates the static service values inside the ServiceLocator and creates an inner class Services, which declares the service constants ( PROJECT and RESOURCE). The Tester client gets an instance to the ServiceLocator singleton and calls getHome(), passing in the PROJECT. ServiceLocator in turn gets the JNDI entry name and the Home class and returns the EJBHome.

Related Patterns

    • Business Delegate 
      The Business Delegate pattern uses Service Locator to gain access to the business service objects such as EJB objects, JMS topics, and JMS queues. This separates the complexity of service location from the Business Delegate, leading to loose coupling and increased manageability.
    • Session Facade 
      The Session Facade pattern uses Service Locator to gain access to the enterprise beans that are involved in a workflow. The Session Facade could directly use the Service Locator or delegate the work to a Business Delegate (See "Business Delegate" on page 248.).
    • Transfer Object Assembler 
      The Transfer Object Assembler pattern uses Service Locator to gain access to the various enterprise beans it needs to access to build its composite Transfer Object. The Transfer Object Assembler could directly use the Service Locator or delegate the work to a Business Delegate (See "Business Delegate" on page 248.).
时间: 2024-11-06 05:44:43

Core J2EE Patterns - Service Locator--oracle官网的相关文章

oracle官网下载老版本jdk + 如何命令行下wget下载jdk

一.文章由来 1.前天有人再去你咨询如何下载jdk的老版本,在oracle官网上找了老半天,找不到相应的选项~ 2.等待问题解决了之后,又抛出来一个新的问题,如何wget直接下载,毕竟百十来兆的文件,下载下来再上传对于我们这种蜗牛带宽来说也是一件苦逼的事情~ 二.如何下载jdk的历史版本 1.访问http://www.oracle.com 2.点击Downloads---->Java for Developers 3.在弹出的的页面中,下拉页面到最下面,点击历史归档 4.点击进去,同意协议,然后

Oracle官网JNI简介和接口函数分析

第一章 概述 本章主要介绍JNI(Java Native Interface),JNI是一种本地编程接口.它允许运行在JAVA虚拟机中的JAVA代码和用其他编程语言,诸如C语言.C++.汇编,写的应用和库之间的交互操作. JNI的最大优势在于没有强加任何限制在JAVA虚拟机的下层实现上,因此,JAVA虚拟机供应商能够提供JNI的支持而不影响虚拟机的其他部分,程序员只需写出一个版本的本地应用和库,就可使之运行在一切支持JNI的JAVA虚拟机上. 本章包含了以下的要点: ? JNI概述 ? 目标 ?

如何在Oracle官网下载历史版本JDK

打开Oracle官网,准备下载java JDK(下载时需要使用注册用户登陆,可以免费注册) 官网地址:http://www.oracle.com/ 2 鼠标悬停Downloads,会出现相关内容,如下图: 3 点击“Java for Developers”,进入JDK下载页面: 4 可以看到下载页面如下,不过是最新的: 5 此页面最下面中有这一项,如下图. 内容大概是: (在Java档案提供一些我们的历史的Java版本. 警告:这些年长的JRE和版本的JDK提供帮助开发人员调试问题在更旧的系统.

Oracle官网JDK的API离线文档下载方法

最近在学习JAVA开发,使用频率最高的工具莫过于JAVA API,当我们身边没有可连接的网络,而又急需API文档时候,很明显我们需要在我们的电脑存储一份离线文档.下面是去Oracle官网下载API Documentation的步骤: 0.在地址栏输入http://www.oracle.com/index.html 进入Oracle官网,如下图: 1.把鼠标移到Downloads那里,不要点它哦!会看到展开一系列Oracle的产品下载,注意到第一列有个叫做“Popular Downloads” 红

如何在Oracle官网下载java的JDK最新版本和历史版本

官网上最显眼位置只显示了Java SE的JDK的最新版本下载链接,因为都是英文,如果英文不是很好,寻找之前的JDK版本需要很长时间,而且未必能在那个隐蔽的位置找到之前版本列表. 今天小编来给你详细讲解下如何在ORACLE官网下载JDK 步骤: 1.打开Oracle官网,准备下载JDK(下载时需要使用注册用户登陆,可以免费注册) 官网地址:http://www.oracle.com/ 2.有账户的直接登录下载,没有的注册一下就可以下载了 3.开始下载JDK.用鼠标将网页拉到最下面 4.进去后,默认

在Oracle官网下载JDK详细步骤

首先进入Oracle官网,链接地址:https://www.oracle.com/cn/downloads/index.html 进入界面后往下滑,在所有下载中点击Java  点击进入后再详细定位到Java的相关下载位置  随后界面会滑动到对应的界面,然后选择红线框内的JDK插件 然后进入界面,选择你想要的版本,我选择的是第二个,然后选择第一个JDK下载 然后等它下载完,再安装就可以了,一般默认安装在C:\Program Files下 原文地址:https://www.cnblogs.com/l

oracle 官网下载

1.官网: http://www.oracle.com/technetwork/database/enterprise-edition/downloads/index.html 2.数据库网址:' http://www.oracle.com/technetwork/database/enterprise-edition/downloads/index.html 3.weblogic 下载网址 http://www.oracle.com/technetwork/middleware/weblogi

Oracle官网下载参考文档

最近有人问我有没有Oracle11g数据库官方参考文档,我就想,这不是在官网可以下载到的吗,疑惑,问了之后才知道,他官网找过,但时没有找到.不要笑,其实有很多人一样是找不到的,下面就一步一步操作下: 1.打开浏览器,输入网址 :www.oracle.com(这步不会的话,建议你可以改行了) 2.找到Menu-->OTN -->Documentation-->Database  点击database后跳转到新的界面 3.选择版本,这里以11gR2为例 5.选好版本后,拉到页面最下面找到do

到Oracle官网下载 Oracle11 G 数据可和客户端操作

1.准备一个Oracle的官网账号 用户名:[email protected] 密码:LR4ever.1314 2.在搜索框中输入Oracle 11 G 3.点击Database Downloadds 4.选中要下载的对应的系统版本 5.下载对应的数据库 原文地址:https://www.cnblogs.com/yvanBk/p/10031767.html