`

Java技术回顾:JNDI应用实例

    博客分类:
  • J2SE
阅读更多

    www.java3z.com/cwbwebhome/article/article2/21040.html
一、JNDI在Java EE中的应用
   JNDI技术是Java EE规范中的一个重要“幕后”角色,它为Java EE容器、组件提供者和应用程序之间提供了桥梁作用:Java EE容器同时扮演JNDI提供者角色,组件提供者将某个服务的具体实现部署到容器上,应用程序通过标准的JNDI接口就可以从容器上发现并使用服务,而不用关心服务的具体实现是什么,它的具体位置在哪里。

    下面以一个常见的J2EE应用场景来看四种角色(组件接口、容器、组件提供者、应用程序)是如何围绕JNDI来发挥作用的:
组件接口
    数据源DataSource是一种很常见的服务。我们通常将组件接口绑定到容器的Context上供客户调用。

Java EE容器
    Tomcat是一种常见的Java EE容器,其他的还有JBoss,WebLogic,它们同时也实现了JNDI提供者规范。容器通常提供一个JNDI注入场所供加入组件的具体实现,比如Tomcat中的Server.xml配置文件。

? 组件提供者
       众多数据库厂商提供了DataSource的实现,比如OracleDataSource,MySQLDataSource,XXXDataSource等。我们将该实现的部署到容器中:将一系列jar加入classpath中,在Server.xml中配置DataSource实现,如:
<Resource name="jdbc/MyDB" auth="Container" type="javax.sql.DataSource" ..../>

应用程序
一个JSP/Servlet应用程序。通过JNDI接口使用DataSource服务,如:
Context initContext = new InitialContext();
Context envContext  = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/MyDB");

关于在Tomcat中如何配置DataSource,可以参考文档:http://tomcat.apache.org/tomcat-5.5-doc/jndi-datasource-examples-howto.html。
关于在Tomcat中如何配置其他JNDI服务,可以参考文档:http://tomcat.apache.org/tomcat-5.5-doc/jndi-resources-howto.html。

二、JNDI实例演练:在Java SE中使用JNDI
   要在Java EE中环境中提供一个独立的实例不太容易。下面以一个独立的Java SE应用来演练JNDI的使用过程。在该应用中,我们使用JNDI来使用两种假想的服务:数据库服务DBService和日志服务LogService。

1、指定JNDI提供者
要使用JNDI,首先要配置JNDI提供者。在我们的Java SE应用中,没有Java EE容器充当JNDI提供者,因此我们要指定其他的JNDI提供者。在我们的例子里,我们使用SUN的文件系统服务提供者File System Service Provider。由于SUN的文件系统服务提供者并没有包含在JDK中,我们需要从SUN网站上下载:http://java.sun.com/products/jndi/downloads/index.html。它包含两个jar文件:fscontext.jar和providerutil.jar。我们将这两个文件加入项目的类路径中。

2、定义服务接口
首先,我们在服务接口package(xyz.service)中定义服务接口:DBService和LogService,分别表示数据库服务和日志服务。

数据库服务接口 DBService.java

package xyz.service;

public interface DBService {
String getLocation(); //获取数据库位置

String getState(); //获取数据库状态

void accessDB(); //访问数据库

void setProperty(int index,String property); //设置数据库信息
}

日志服务接口 LogService.java

package xyz.service;

public interface LogService {
void log(String message); //记录日志
}

3、组件提供者实现服务接口
  接下来,我们在组件提供者package(xyz.serviceprovider)中提供DBService和LogService的实现:SimpleDBService和SimpleLogService。为了让服务能够在JNDI环境中使用,根据JNDI规范,我们同时定义两个对象工厂类SimpleDBServiceFactory和SimpleLogServiceFactory,分别用来创建服务实例。

数据库服务接口实现  SimpleDBService.java

package xyz.serviceprovider;

import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;

import xyz.service.DBService;

//为了将数据库服务实例加入JNDI的Context中,我们需要实现Referenceable接口,并实现RetReference方法。
//关于Reference和Referenceable,请参考上一篇:Java技术回顾之JNDI:JNDI API
public class SimpleDBService implements Referenceable, DBService {
private String location="mydb//local:8421/defaultdb";//数据库服务属性之一:数据库位置
private String state="start"; //数据库服务属性之二:数据库状态

public Reference getReference() throws NamingException {
  //Reference是对象的引用,Context中存放的是Reference,为了从Reference中还原出对象实例,
  //我们需要添加RefAddr,它们是创建对象实例的线索。在我们的SimpleDBService中,location和state是这样两个线索。
  Reference ref=new Reference(getClass().getName(),SimpleDBServiceFactory.class.getName(),null);
  ref.add(new StringRefAddr("location",location));
  ref.add(new StringRefAddr("state",state));
  return ref;
}

public void accessDB() {
  if(state.equals("start"))
   System.out.println("we are accessing DB.");
  else
   System.out.println("DB is not start.");
}

public String getLocation() {
  return location;
}

public String getState() {
  return state;
}

public void setProperty(int index,String property){
  if(index==0)
   location=property;
  else
   state=property;
}
}

数据库服务对象工厂类 SimpleDBServiceFactory.java

package xyz.serviceprovider;

import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;

//数据库服务对象工厂类被JNDI提供者调用来创建数据库服务实例,对使用JNDI的客户不可见。
public class SimpleDBServiceFactory implements ObjectFactory {

//根据Reference中存储的信息创建出SimpleDBService实例
public Object getObjectInstance(Object obj, Name name, Context ctx,
   Hashtable<?, ?> env) throws Exception {
  if(obj instanceof Reference){
   Reference ref=(Reference)obj;
   String location=(String)ref.get("location").getContent();
   String state=(String)ref.get("state").getContent();
   SimpleDBService db= new SimpleDBService();
   db.setProperty(0, location);
   db.setProperty(1, state);
   return db;
  }
  return null;
}
}

日志服务接口实现 SimpleLogService.java

package xyz.serviceprovider;

import java.text.SimpleDateFormat;
import java.util.Date;

import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;

import xyz.service.LogService;

public class SimpleLogService implements Referenceable, LogService {
private SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

//SimpleLogService没有任何属性,通过SimpleLogService类名创建出来的SimpleLogService实例都是一样的,
//因此这里无需添加RefAddr了。
public Reference getReference() throws NamingException {
  return new Reference(getClass().getName(),SimpleLogServiceFactory.class.getName(),null);
}

public void log(String message) {
  String date=sdf.format(new Date());
  System.out.println(date+":"+message);
}
}

日志服务对象工厂类 SimpleLogServiceFactory.java

package xyz.serviceprovider;

import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;

public class SimpleLogServiceFactory implements ObjectFactory {

public Object getObjectInstance(Object obj, Name name, Context ctx,
   Hashtable<?, ?> env) throws Exception {
  if(obj instanceof Reference){
   return new SimpleLogService();
  }
  return null;
}
}

4、JNDI容器和JNDI客户端
    最后,我们在JNDI应用package(xyz.jndi)中实现一个JNDI容器JNDIContainer和一个JNDI客户端应用JNDIClient。
JNDIContainer在内部使用文件系统服务提供者fscontext来提供命名和目录服务,配置文件JNDIContainer.properties是服务注入场所,供配置DBService和LogService实现。

JNDI容器类 JNDIContainer.java

package xyz.jndi;

import java.io.InputStream;
import java.util.Hashtable;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import xyz.service.DBService;
import xyz.service.LogService;

public class JNDIContainer {

private Context ctx=null;

public void init() throws Exception{
     //初始化JNDI提供者。
     Hashtable env = new Hashtable();
     env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
     env.put(Context.PROVIDER_URL, "file:/c:/sample"); //fscontext的初始目录,我们需要在c:\下创建sample目录。
     ctx=new InitialContext(env);
     loadServices();
}

//从配置文件JNDIContainer.properties中读取DBService和LogService实现,绑定到Context中。
private void loadServices() throws Exception{
  InputStream in=getClass().getResourceAsStream("JNDIContainer.properties");
  Properties props=new Properties();
  props.load(in);
 
  //inject dbservice
  String s=props.getProperty("DBServiceClass");
  Object obj=Class.forName(s).newInstance();
  if(obj instanceof DBService){
   DBService db=(DBService)obj;
   String[] ss=props.getProperty("DBServiceProperty").split(";");
   for(int i=0;i<ss.length;i++)
    db.setProperty(i, ss[i]);
   ctx.rebind(props.getProperty("DBServiceName"), db);
  }
 
  //inject logservice
  s=props.getProperty("LogServiceClass");
  obj=Class.forName(s).newInstance();
  if(obj instanceof LogService){
   LogService log=(LogService)obj;
   ctx.rebind(props.getProperty("LogServiceName"), log);
  }
}

public void close() throws NamingException{
  ctx.close();
}

public Context getContext(){
  return ctx;
}
}

JNDI容器配置文件 JNDIContainer.properties

//和JNDIContainer.java文件位于同一目录
DBServiceName=DBService
DBServiceClass=xyz.serviceprovider.SimpleDBService
DBServiceProperty=mydb//192.168.1.2:8421/testdb;start

LogServiceName=LogService
LogServiceClass=xyz.serviceprovider.SimpleLogService

JNDI客户端 JNDIClient.java

package xyz.jndi;

import javax.naming.Context;

import xyz.service.DBService;
import xyz.service.LogService;

public class JNDIClient {

public static void main(String[] args){
  try{
   JNDIContainer container=new JNDIContainer();
   container.init();
  
      //JNDI客户端使用标准JNDI接口访问命名服务。
      Context ctx=container.getContext();
      DBService db=(DBService)ctx.lookup("DBService");
      System.out.println("db location is:"+db.getLocation()+",state is:"+db.getState());
      db.accessDB();
    
      LogService ls=(LogService)ctx.lookup("LogService");
      ls.log("this is a log message.");
    
      container.close();
  }
  catch(Exception e){
   e.printStackTrace();
  }
}
}

至此,我们的整个Java SE应用已经完成。下面是整个应用的源代码结构(Eclipse工程):

jndisample project
分享到:
评论

相关推荐

    java面试宝典

    【Java面试宝典】是为Java开发者准备的一份详尽的面试指南...这些内容旨在帮助求职者回顾和强化Java技术栈,确保在面试中能够应对各种技术问题,从而提高成功几率。不断学习和更新知识,是适应快速发展的IT行业的关键。

    Java Programming 24-Hour Trainer

    - **封装、继承与多态性**:学习面向对象编程中的三大特性,并通过实例演示其应用。 - **抽象类与接口**:了解抽象类和接口的定义,以及它们之间的区别。 ##### 4. 类的方法 (Lesson4) - **方法的定义与调用**:...

    j2ee详细开发介绍课件

    **J2EE(Java 2 Platform, Enterprise Edition)**是一个由Oracle公司提供的企业级应用开发平台,主要用于构建分布式、多层...而对于经验丰富的开发者,回顾这些基础知识和实例分析有助于巩固和提升你的J2EE技术水平。

    J2EE集群.pdf

    - **定义**:每台服务器维护自己的JNDI实例,这种方式可能会影响数据的一致性。 - **应用场景**:适用于对性能要求较高且能够接受一定程度的数据不一致性的场景。 **5.3 中央集中JNDI** - **定义**:所有服务器...

    JSP 程序设计从入门到精通 PDF 教程

    - 这部分讨论了如何使用JNDI(Java Naming and Directory Interface)来查找和配置RowSet对象。 ##### 6.5 RowSet之实践 - 这部分通过示例介绍了如何在实际开发中使用RowSet对象。 ##### 6.6 本章小结 - 对本章...

    黑魔方jsp网络编程代码

    9. **JNDI(Java Naming and Directory Interface)**:在企业级应用中,JNDI常用于查找和管理资源,如数据库连接池、EJB等。 10. **部署描述符(web.xml)**:这是Java Web应用的配置文件,定义了应用的初始化参数...

    Spring3.x企业应用开发实战(完整版) part1

    《Spring3.x企业应用开发实战》是在《精通Spring2.x——企业应用开发详解》的基础上,经过历时一年的重大调整改版而成的,本书延续了上一版本追求深度,注重原理,不停留在技术表面的写作风格,力求使读者在熟练使用...

    Spring.3.x企业应用开发实战(完整版).part2

    《Spring3.x企业应用开发实战》是在《精通Spring2.x——企业应用开发详解》的基础上,经过历时一年的重大调整改版而成的,本书延续了上一版本追求深度,注重原理,不停留在技术表面的写作风格,力求使读者在熟练使用...

    hibernate3.5.4全中文帮助文档

    ### Hibernate 3.5.4 全中文帮助文档知识点概览 ...以上内容涵盖了从环境搭建到高级特性使用的各个方面,旨在帮助初学者全面了解Hibernate的核心概念和技术细节,从而能够熟练地运用Hibernate进行Java应用开发。

    hibernate 帮助文档

    - **学习成果**:回顾本章节所学的主要概念和技术。 - **实践建议**:提供进一步的学习资源和实践建议。 #### 二、体系结构(Architecture) **2.1 概况(Overview)** - **整体架构**:概述Hibernate的体系结构...

    hibernate 中文参考手册

    - **加载和保存实例**:演示如何使用 Hibernate 来加载和保存实体类实例。 ##### 1.2 第二部分:关联映射 **1.2.1 映射 Person 类** 这部分介绍了如何映射一个包含关联关系的实体类。 - **实体设计**:解释 ...

    Hibernate Reference Documentation

    - **JNDI绑定SessionFactory**:介绍如何使用JNDI绑定SessionFactory。 - **JTA会话上下文管理**:解释如何在JTA环境中管理当前会话。 - **JMX部署**:说明如何通过JMX部署和管理Hibernate。 #### 四、持久化类 **...

    JBoss架构分析

    1. **文献回顾**:收集关于JBoss架构的相关资料,包括官方文档、学术论文和技术博客等。 2. **源码分析**:利用逆向工程工具对JBoss源代码进行深入研究,以便更好地理解其内部组件之间的相互作用。 3. **模型构建**...

    Hibernate 3.x 参考手册

    - 使用 Hibernate 前需确保 Java 环境已安装配置。 - 下载 Hibernate 3.x 版本库文件,并将其添加到项目类路径中。 - 配置 Hibernate 的核心配置文件(如 `hibernate.cfg.xml`)。 - **示例代码:** ```java ...

    spring2.5 -3.0 hibernate3.3 jar包说明

    它还提供了与JNDI的集成,支持Web应用程序中的环境特性。 5. **spring-dao.jar** 提供了异常层次结构,它使开发者能够以一致的方式处理不同的数据访问技术引发的数据访问异常。 6. **spring-hibernate.jar** ...

Global site tag (gtag.js) - Google Analytics