J2EE——JNDI

 看了一些资料,觉得都很不错,对我很有帮助。整理了一下,分享给大家(非原创)。

第一部分:什么是JNDI

第二部分:为什么要用JNDI

第三部分:怎么用JNDI(以及常用jndi类的介绍)

第四部分:在使用JNDI是要注意的事项

 

第一部分:什么是JNDI

1,名词解释:

  • Java命名和目录接口(the Java naming and directory interfaceJNDI)是一组在Java应用中访问命名和目录服务的API。为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口,类似JDBC都是构建在抽象层上。
    命名服务将名称和对象联系起来,使得读者可以用名称访问对象。目录服务是一种命名服务,在这种服务里,对象不但有名称,还有属性。
  • 命名服务:就像DNS一样,通过命名服务器提供服务,大部分的J2EE服务器都含有命名服务器。例如:http://202.108.22.5/
  • 目录服务:一种简化的RDBMS系统,通过目录具有的属性保存一些简单的信息。目录服务通过目录服务器实现,比如微软ACTIVE DIRECTORY等。
  • 我的理解
    • 用过名字来查找对象,你给我一个名字,我给你一个对象。跟我们去图书馆借书差不多,当然是以前的那种方式,我们说一书名,然后工作人员那着我们给他的书名在目录中查找,在去书架上找书,在借给我们。
    • 将对象和名字捆绑的技术,对象工厂负责生产出对象,这些对象都和唯一的名字绑在一起,外部资源可以通过名字获得某对象的引用。

2JNDI可以访问的目录及服务:

DNSXNamNovell目录服务、LDAP(LightweightDirectory Access Protocol轻型目录访问协议)CORBA对象服务、文件系统、Windows XP/2000/NT/Me/9x的注册表、RMIDSML v1&v2NIS

3JNDI原理

将对象和名字捆绑的技术,对象工厂负责生产出对象,这些对象都和唯一的名字绑在一起,外部资源可以通过名字获得某对象的引用。


4JNDI架构


JNDI架构的理解:

  • JNDI的架构与JDBC的架构非常类似.JNDI架构提供了一组标准命名系统的API。在应用程序中,我们实际上只使到用以上几个包的中类.具体调用类及通信过程对用户来说是透明的. JNDI API提供了访问不同JNDI服务的一个标准的统一的实现,其具体实现可由不同的Service Provider来完成。
  • 中间层为命名管理层。其功能应该由JNDI SPI来完成。
  • 最下层为JNDI SPI API及其具体实现 

包括了几个增强和下面的命名/目录服务提供者:

  • LDAP(Lightweight Directory Access Protocol)服务提供者
  • CORBA COSCommon Object Request Broker Architecture Common Object Services)命名服务提供者 
  • RMI(Java Remote Method Invocation)注册服务提供者
  • DNS(Domain Name System)服务提供者.
  • FSSP(File System Service Provider)文件系统服务提供者
  • 其它服务提供者
  • 前面讲解的只是作为应用程序客户端的架构实现,其服务端是由SPI对应的公司/厂商来实现的,我们只需将服务端的相关参数传给JNDI API就可以了,具体调用过程由SPI来完成.

 

第二部分:为什么要用JNDI

1

  • 为了实现共享,计算机网络的发展就是为了达到资源的共享
  • 命名或目录服务使读者可以集中存储共有信息,这一点在网络应用中是非常重要的,因为这使得这样的应用更协调、更容易管理。例如,可以将打印机设置存储在目录服务中,以便被与打印机有关的应用使用。

jndi诞生的理由似乎很简单。随着分布式应用的发展,远程访问对象访问成为常用的方法。虽然说通过Socket等编程手段仍然可实现远程通信,但按照模式的理论来说,仍是有其局限性的。RMI技术,RMI-IIOP技术的产生,使远程对象的查找成为了技术焦点。JNDI技术就应运而生。JNDI技术产生后,就可方便的查找远程或是本地对象。

2,用来解决什么问题

(1)数据共享

命名或目录服务使读者可以集中存储共有信息,这一点在网络应用中是非常重要的,因为这使得这样的应用更协调、更容易管理。例如,可以将打印机设置存储在目录服务中,以便被与打印机有关的应用使用。

(2)分布式应用

 jndi诞生的理由似乎很简单。随着分布式应用的发展,远程访问对象访问成为常用的方法。虽然说通过Socket等编程手段仍然可实现远程通信,但按照模式的理论来说,仍是有其局限性的。RMI技术,RMI-IIOP技术的产生,使远程对象的查找成为了技术焦点。JNDI技术就应运而生。JNDI技术产生后可方便查找远程和本地对象。

(3)解决紧耦合问题

 

3,如果不用JNDI我们怎么解决之前的问题?

(1)没有JNDI的做法

举个数据库连接的例子

程序员开发时,知道要开发访问MySQL数据库的应用,于是将一个对MySQLJDBC 驱动程序类的引用进行了编码,并通过使用适当的JDBCURL 连接到数据库。

就像以下代码这样:

Connection conn=null;

try    { Class.forName("com.mysql.jdbc.Driver",true,Thread.currentThread().getContextClassLoader()); conn=DriverManager.getConnection("jdbc:mysql://MyDBServer?user=qingfeng&password=mingyue");  /*使用conn并进行SQL操作

*/  ...... conn.close();}

catch(Exception e)

{  e.printStackTrace();}

finally {  if(conn!=null)

 { try { conn.close();    } catch(SQLException e) {}  }}

   这是传统的做法,也是以前非Java程序员(如DelphiVB等)常见的做法。这种做法一般在小规模的开发过程中不会产生问题,只要程序员熟悉Java语言、了解JDBC技术和MySQL,可以很快开发出相应的应用程序。

4,优缺点

  • 这样做的优点
    • 简单
  • 这样做的有的缺点
    • 可扩展行差
      • 数据库名称,用户名,密码可能随时改变,这时就的修改代码
      • 数据库产品的修改
      • 终端用户的增加

5,解决方法

  • 程序员应该不需要关心“具体的数据库后台是什么?JDBC驱动程序是什么?JDBC URL格式是什么?访问数据库的用户名和口令是什么?”等等这些问题,程序员编写的程序应该没有对JDBC 驱动程序的引用,没有服务器名称,没有用户名称或口令 ——甚至没有数据库池或连接管理。而是把这些问题交给J2EE容器来配置和管理,程序员只需要对这些配置和管理进行引用即可。就这样JNDI诞生了。

6JNDI的做法

  • 概述
    • 首先,在在J2EE容器中配置JNDI参数,定义一个数据源,也就是JDBC引用参数,给这个数据源设置一个名称;然后,在程序中,通过数据源名称引用数据源从而访问后台数据库。
  • 具体步骤
    • J2EE容器中配置JNDI参数,例如在jboss中的发布目录中的数据库XML文件中配置数据源
  • 通过Lookup来获取数据源对象

7,运行机制

(1)首先程序代码获取初始化的JNDI 环境并且调用 Context.lookup()方法从 JNDI 服务提供者那里获一个DataSource 对象。

(2)中间层JNDI 服务提供者返回一个 DataSource对象给当前的 Java 应用程序这个DataSource 对象代表了中间层服务上现存的缓冲数据源。

(3)应用程序调用DataSource 对象的 getConnection()方法

(4)DataSource 对象的 getConnection()方法被调用时,中间层服务器将查询数据库 连接缓冲池中有没有PooledConnection接口的实例对象。这个 PooledConnection 对象将被用于与数据库建立物理上的数据库连接

(5)如果在缓冲池中命中了一个PooledCoonection 对象那么连接缓冲池将简单地更新内部的缓冲连接队列并将该 PooledConnection对象返回。如果在缓冲池内没 有找到现成的PooledConnection 对象,那么ConnectionPoolDataSource接口将会被 用来产生一个新的PooledConnection 对象并将它返回以便应用程序使用

(6)中间层服务器调用 PooledConnection对象的getConnection() 方法以便返还一个 java.sql.Connection 对象给当前的 Java应用程序

(7)当中间层服务器调用 PooledConnection对象的getConnection() 方法时, JDBC数据 库驱动程序将会创建一个Connection对象并且把它返回中间层服务器

(8)中间层服务器将Connection 对象返回给应用程序 Java应用程序,可以认为这个 Connection对象是一个普通的JDBC Connection 对象使用它可以和数据库建立。事实上的连接与数据库引擎产生交互操作

(9)当应用程序不需要使用Connection 对象时,可以调用Connection接口的 close() 法。请注意这种情况下 close()方法并没有关闭事实上的数据库连接,仅仅是释放了被应用程序占用的数据库连接,并将它还给数据库连接缓冲池,数据库连接 缓冲池会自动将这个数据库连接交给请求队列中下一个的应用程序使用。

8优缺点

1)优点:

  • 包含大量命名和目录服务,可以使用相同API调用访问任何命名或目录服务。
  • 可以同时连接多个命名和目录服务。
  • 允许把名称同JAVA对象或资源关联起来,不必知道对象或资源的物理ID
  • 使用通用接口访问不同种类的目录服务
  • 使得开发人员能够集中使用和实现一种类型的命名或目录服务客户API

2)缺点:

  • 配置很繁琐
  • 调试很困难

 

第三部分:怎么用JNDI

1,在什么情况下使用JNDI

  • 比较大型的软件开发中
  • 比较重视后期的维护和升级的项目中
  • 分布式系统中

2JNDI的包

  • Javax.naming
    • 主要用于命名操作,它包含了命名服务的类和接口,该包定义了Context接口和InitialContext类;
  • Javax.naming.directory
    • 主要用于目录操作,它定义了DirContext接口和InitialDir- Context类;
  • Javax.naming.event
  • Javax.naming.event
    • 在命名目录服务器中请求事件通知;
  • javax.naming.ldap
    • 提供LDAP支持;
  • javax.naming.spi
    • 允许动态插入不同实现,为不同命名目录服务供应商的开发人员提供开发和实现的途径,以便应用程序通过JNDI可以访问相关服务。

3,常用JNDI操作

  • void bind(String sNameObject object),绑定:把名称同对象关联的过程。
  • void rebind(String sNameObject object),重新绑定:用来把对象同一个已经存在的名称重新绑定。一般使用rebind()而不使用bind(),因为当有重名的时候rebind()不会出现异常,而bind()会报异常。
  • void unbind(String sName),释放:用来把对象从目录中释放出来。
  • void lookup(String sNameObject object),查找:返回目录中的一个对象。
  • void rename(String sOldNameString sNewName),重命名:用来修改对象名称绑定的名称。 
  • NamingEnumeration listBindings(String sName),清单:返回绑定在特定上下文中指定属性名对象的清单列表,它返回名字、类和对象本身,它用于那些需要对对象进行实际操作的应用。具体使用如下 :
    • 得到初始目录环境的一个引用
      • Context cntxt = new InitialContext();
    • 返回绑定在特定上下文中指定属性名对象的清单列表

NamingEnumeration namEnumList =ctxt.listBinding("cntxtName");

  • 循环列出所有名字、类和对象

while ( namEnumList.hasMore() ) {

   Binding bnd = (Binding)namEnumList.next();

    String sObjName =bnd.getName();

    String sClassName =bnd.getClassName();

  • 得到对象

SomeObject objLocal = (SomeObject)bnd.getObject(); }

NamingEnumerationlist(String sName)listBindings(String sName)相似,只是它只返回一系列名字/类映射,它主要是用于上下文浏览应用。

 

4JNDI操作步骤

使用JNDI来访问命名服务或者目录服务,操作步骤如下:

  • 1、建立一个散列表(hashtable),它包含定义所希望使用的JNDI服务的属性,所希望连接的LDAP服务器IP地址以及工作的端口。
  • 2、将与认证成为用户登录有关的任何信息添加到散列表中 
  • 3、创建初始context对象。如果访问命名服务,则使用InitialContext类,如果访问目录服务,则要使用InitialDirContext类。
  • 4、使用刚才得到的context对象执行所需的操作(如添加新的条目或者搜索条目)。
  • 5、完成操作后关闭context对象。

5JNDI实例

(1)访问Jboss 服务器的例子代码:

Properties props = new Properties();

props.setProperty("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");

props.setProperty("java.naming.provider.url","localhost:1099");

InitialContext = new InitialContext(props);

HelloWorld helloworld = (HelloWorld)ctx.lookup("HelloWorldBean/remote");

(2)访问Sun 应用服务器的例子代码:

Properties props = newProperties();
props.setProperty("java.naming.factory.initial",
"com.sun.enterprise.naming.SerialInitContextFactory");
props.setProperty("java.naming.provider.url", "localhost:3700");
InitialContext = new InitialContext(props);
HelloWorld helloworld = (HelloWorld)ctx.lookup("com.foshanshop.ejb3.HelloWorld");

(3)访问Weblogic10 应用服务器的例子代码:

Properties props = newProperties();
props.setProperty("java.naming.factory.initial","weblogic.jndi.WLInitialContextFactory");
props.setProperty("java.naming.provider.url","t3://localhost:7001");
InitialContext = new InitialContext(props);
HelloWorld helloworld = (HelloWorld)ctx.lookup("HelloWorldBean#com.foshanshop.ejb3.HelloWorld");


6JNDI数据库实例

JNDI连接数据库模型

package DBUtil;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import javax.naming.Context;
import javax.naming.InitialContext;
public class DBConnection {
   private Connection conn = null;
   private Statement stmt = null;
   private ResultSet rs = null;
   private int resultNum = 0;
  
   public DBConnection() {
       try {
            Context ctx = new InitialContext();
    if (ctx == null) throw new Exception("No Context");
    DataSource ds =(DataSource)ctx.lookup("java:comp/env/jdbc/oracle");
            if (ds == null) throw newException("jdbc/oracle is an unknown DataSource");
            conn = ds.getConnection();
            stmt = conn.createStatement();
       } catch (Exception e) {
           System.out.println("naming:" + e.getMessage());
       }
   }
   public ResultSet executeQuery(String sql) {
       rs = null;
       try {
            rs = stmt.executeQuery(sql);
       } catch(SQLException se) {
            System.out.println("Queryerror:" + se.getMessage());
       }
       return rs;
   }
  
   public int executeUpdate(String sql) {
       resultNum=0;
       try {
            resultNum =stmt.executeUpdate(sql);
       } catch (SQLException se) {
            System.err.println("Updateerror:" + se.getMessage());
       }
       return resultNum;
   }
public void close() {
       try {
            if (rs != null) {
                rs.close();
                rs = null;
            }
            if (stmt != null) {
               stmt.close();
               stmt = null;
            }
            if (conn != null) {
                conn.close();
                conn = null;
            }
       } catch (SQLException se) {
            System.out.println("closeerror:" + se.getMessage());
       }
   }
} 




评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值