`
fj_ding
  • 浏览: 36889 次
社区版块
存档分类
最新评论

JNDI理解与实例

    博客分类:
  • java
阅读更多

本文转载于http://blog.csdn.net/xiancaieeee/article/details/7881441
因为原文代码排列比较乱,只是进行了稍加整理一下


一、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应用已经完成

分享到:
评论
1 楼 edidada 2019-07-24  
有完整的代码不?

相关推荐

    用jndi操作数据库小实例

    在Java开发中,JNDI(Java ...通过这个小实例,开发者可以理解JNDI和数据源在Java EE应用中的重要性,以及它们如何简化数据库连接管理和提高性能。了解并掌握这些知识,对于开发高效、可扩展的企业级应用是至关重要的。

    log4j\c3p0\jndi详细配置实例

    在Java开发中,日志管理和数据库连接池是两个至关重要的组件。`log4j`是广泛使用的日志记录框架,而`c3...通过学习和理解这个实例,开发者可以更好地管理日志输出,优化数据库连接,以及利用JNDI服务来管理和查找资源。

    Tomcat6.0 JNDI数据源经典实例

    总结来说,这个Tomcat 6.0 JNDI数据源经典实例提供了从配置到使用的全过程,包括了必要的文件和脚本,便于开发者理解和实践JNDI数据源在实际项目中的应用。正确配置和使用JNDI数据源能有效管理和优化数据库连接,...

    从实例看JNDI设计

    通过JNDI,开发者可以将应用程序与具体的资源定位细节解耦,使应用更加灵活和可扩展。 **JNDI工作原理** JNDI主要由两部分组成:Name Space(命名空间)和Naming Context(命名上下文)。Name Space是一个逻辑结构...

    技术专栏 _ 深入理解JNDI注入与Java反序列化漏洞利用.pdf

    文章中提到了JdbcRowSetImpl利用链和FastJson反序列化漏洞,这些是JNDI注入攻击利用的实例。JdbcRowSetImpl是Java的一个类,它允许通过JNDI进行远程调用。FastJson是一个广泛使用的Java库,用于对象到JSON的序列化与...

    用JNDI建立数据库连接池实例

    在这个实例中,我们将讨论如何在基于Tomcat的Web服务器上使用JNDI来创建数据库连接池。 首先,理解JNDI的工作原理至关重要。JNDI的核心是名称绑定,即将一个名称(比如“jdbc/myDataSource”)与一个对象(如数据库...

    jndi使用实例

    本文将深入探讨JNDI的使用实例,帮助开发者更好地理解和应用这一技术。 首先,我们需要了解JNDI的基本概念。JNDI是一个服务提供商接口(SPI),允许应用程序查找和操作存储在不同类型的命名和目录系统中的数据。...

    JNDIDemo 以及相关文档

    8. **JNDI与EJB和JDBC**:在Enterprise JavaBeans (EJB) 中,JNDI用于查找和注入EJB实例。在Java Database Connectivity (JDBC) 中,数据源通常通过JNDI查找来获取,这样可以轻松地在不同环境中配置数据库连接。 9....

    JNDI简单应用示例

    这个"JNDI简单应用示例"可能是演示如何使用JNDI进行基本操作的代码实例,例如: 1. **初始化Naming Context**:首先,你需要创建一个初始上下文(InitialContext),这是所有JNDI操作的起点。这通常通过传递一个...

    JNDI学习文档.doc

    - **松耦合**:JNDI允许应用程序与资源之间保持松散耦合,因为它们之间的联系是通过名称而不是硬编码的实例引用。 - **可扩展性**:随着系统的发展,可以轻松添加新的命名或目录服务,而无需修改现有代码。 - **集中...

    tomcat配置jndi

    2. **JNDI实例化** 在应用程序中,你可以通过JNDI查找刚创建的数据源。以下是一个简单的Java代码示例: ```java Context initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup("java:...

    jndi配置

    JNDI(Java Naming and Directory Interface)是Java平台中用于...理解并正确使用JNDI,可以极大地提高Java应用的灵活性、可维护性和安全性。在实际项目中,我们需要根据服务器环境和应用需求来配置和利用JNDI服务。

    tomcat-jndi

    本篇文章将深入探讨Tomcat与JNDI的结合使用,帮助开发者更好地理解和利用这一特性。 JNDI是Java应用程序访问命名和目录服务的一个统一接口,它允许开发者透明地访问多种不同的命名和目录服务,如 LDAP、DNS等。在...

    jndi连接数据库配置方法

    首先,创建一个`InitialContext`实例,然后调用其`lookup()`方法,传入你之前设定的JNDI名称,例如`"java:comp/env/jdbc/MyDB"`。 ```java Context initialContext = new InitialContext(); DataSource ...

    04_JNDI.pdf

    - **EJB Home Stub及EJB环境变量**:在EJB(Enterprise JavaBeans)环境中,JNDI用来查找EJB的Home接口,以及EJB实例的环境配置信息。 - **JDBC DataSource**:用于查找和管理数据库连接资源。 - **JMS Connection ...

    JNDI配置原理详解.doc

    本文将详细介绍JNDI配置原理,并通过具体的示例帮助读者更好地理解和应用JNDI。 #### 二、JNDI基本概念 JNDI提供了一个通用的API,用于查找和管理分布式环境中各种命名和目录服务。这些服务包括但不限于DNS、LDAP...

    spring 配置jndi

    - 为了测试JNDI配置是否正确,你可以尝试从Spring应用上下文中获取数据源并打印其信息,确保能成功查找并实例化。 6. **扩展性与最佳实践**: - 考虑使用Spring Boot,它提供了更简洁的方式来配置JNDI数据源,只...

    JNDI使用

    在实际开发中,理解并熟练掌握JNDI的使用,能够极大地提高开发效率和代码的可维护性。如果你想要进一步深入,可以参考提供的博客链接:[https://canofy.iteye.com/blog/613841]...

    初学jndi笔记

    **JNDI**(Java Naming and Directory Interface)是Java平台的一部分,用于开发与名称和服务目录进行交互的应用程序。它允许Java应用程序查找并使用远程对象和服务。在J2EE环境中,JNDI提供了一种标准化的方式来...

    jndi 数据库连接池 & 监听

    本资源包含对JNDI数据库连接池的详细讲解,以及监听器的代码实例和讲解资料,旨在帮助开发者更好地理解和应用这些技术。JNDI主要通过以下步骤实现数据库连接的管理: 1. **配置JNDI数据源**:在应用服务器(如...

Global site tag (gtag.js) - Google Analytics