JNDI学习三

来源:互联网 发布:疯狂java讲义好不好 编辑:程序博客网 时间:2024/04/20 12:11

第二部分:为什么要用JNDI

•为了实现共享,计算机网络的发展就是为了达到资源的共享

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

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

用来解决什么问题

1、数据共享

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

2、分布式应用

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

3、解决紧耦合问题

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

1、没有JNDI的做法

举个数据库连接的例子

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

就像以下代码这样:

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程序员(如Delphi、VB等)常见的做法。这种做法一般在小规模的开发过程中不会产生问题,只要程序员熟悉Java语言、了解JDBC技术和MySQL,可以很快开发出相应的应用程序。

优缺点

•这样做的优点

–简单

•这样做的有的缺点

–可扩展行差

•数据库名称,用户名,密码可能随时改变,这时就的修改代码

•数据库产品的修改

•终端用户的增加

•解决办法

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

JNDI的做法:

•概述

–首先,在在J2EE容器中配置JNDI参数,定义一个数据源,也就是JDBC引用参数,给这个数据源设置一个名称;然后,在程序中,通过数据源名称引用数据源从而访问后台数据库。

•具体步骤

–在J2EE容器中配置JNDI参数,例如在jboss中的发布目录中的数据库XML文件中配置数据源

–通过Lookup来获取数据源对象

运行机制-1

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() 方法并没有关闭事实上的数据库连接,仅仅是释放了被应用程序占用的数据库连接,并将它还给数据库连接缓冲池,数据库连接缓冲池会自动将这个数据库连接交给请求队列中下一个的应用程序使用。

优点

–包含大量命名和目录服务,可以使用相同API 调用访问任何命名或目录服务。

–可以同时连接多个命名和目录服务。

–允许把名称同JAVA 对象或资源关联起来,不必知道对象或资源的物理ID。

–使用通用接口访问不同种类的目录服务

–使得开发人员能够集中使用和实现一种类型的命名或目录服务客户API 上

缺点

–配置很繁琐

–调试很困难

第三部分:怎么用JNDI

•在什么情况下使用JNDI

•具体怎么使用

•有哪几种使用方式

•比较大型的软件开发中

•比较重视后期的维护和升级的项目中

•分布式系统中

•Javax.naming

–主要用于命名操作,它包含了命名服务的类和接口,该包定义了Context接口和InitialContext类;

•Javax.naming.directory

–主要用于目录操作,它定义了DirContext接口和InitialDir- Context类;

•Javax.naming.event

–在命名目录服务器中请求事件通知;

•javax.naming.ldap

–提供LDAP支持;

•javax.naming.spi

–允许动态插入不同实现,为不同命名目录服务供应商的开发人员提供开发和实现的途径,以便应用程序通过JNDI可以访问相关服务。

常用JNDI操作

• void bind(String sName,Object object),绑定:把名称同对象关联的过程。

•void rebind(String sName,Object object),重新绑定:用来把对象同一个已经存在的名称重新绑定。一般使用rebind()而不使用bind(),因为当有重名的时候rebind()不会出现异常,而bind()会报异常。

•void unbind(String sName),释放:用来把对象从目录中释放出来。

•void lookup(String sName,Object object),查找:返回目录中的一个对象。

•void rename(String sOldName,String 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(); }

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

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

–1、建立一个散列表(hashtable),它包含定义所希望使用的JNDI服务的属性,所希望连接的LDAP服务器IP地址以及工作的端口。

–2、将与认证成为用户登录有关的任何信息添加到散列表中

–3、创建初始context对象。如果访问命名服务,则使用InitialContext类,如果访问目录服务,则要使用InitialDirContext类。

–4、使用刚才得到的context对象执行所需的操作(如添加新的条目或者搜索条目)。

–5、完成操作后关闭context对象。

JNDI实例

•访问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");

•访问Sun 应用服务器的例子代码:

•Properties props = new Properties();
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");

•访问Weblogic10 应用服务器的例子代码:

•Properties props = new Properties();
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");

•public enum ServerType {

•JBOSS, WEBLOGIC,GLASSFISH;

•@SuppressWarnings("unchecked")

•public String getJndiName(Class service, String mappingName) {

•switch (this) {

•case JBOSS:

•return mappingName + "/remote";

•case WEBLOGIC:

•return mappingName + "#" + service.getName();

•case GLASSFISH:

•return service.getName();

•}

•return mappingName + "/remote";

•}

•}

Jndi数据库实例

•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 new Exception("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("Query error:" + se.getMessage());

• }

• return rs;

• }

• public int executeUpdate(String sql) {

• resultNum=0;

• try {

• resultNum = stmt.executeUpdate(sql);

• } catch (SQLException se) {

• System.err.println("Update error:" + 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("close error:" + se.getMessage());

• }

• }

•}

原创粉丝点击