JNDI

一、JNDI

       1.1 JNDI 的客户端开发简介

 

JNDI 的客户端开发包括下列步骤:

1.创建初始化上下文(IntialContext)。它相当于打开文件浏览器,就像要找文件先要打Windows 上的“我的电脑”一样。对本地客户端(例如同一台服务器上的EJB 或者Web层的Servlet 中),可以直接初始化上下文:

Context ctx = new IntialContext();

对任意客户端的话,则需要设置一些初始化的参数:

Hashtable ht = new Hashtable();

// 设置工厂类(指定SPI),不同的服务器取值不同

ht.put

(Context.INITIAL_CONTEXT_FACTORY, ”org.jnp.interfaces.NamingContextFactory”);

// 指定要连接的服务器地址(相当于JDBC URL

ht.put(Context.PROVIDER_URL,” jnp://localhost”);//如果要加端口,地址为:jnp://host:port

// 可以设置服务器的用户名和密码(也和JDBC 类似)

//ht.put(Context.SECURITY_PRINCIPAL,”user”);

//ht.put(Context.SECURITY_CREDENTIALS,”password”);

Context ctx = new InitialContext (ht);

当然编写这一步的时候需要确保放入了驱动类。不同的服务器,驱动程序类(Context

Factory)和URL 都是不一样的。

然而这样要写很多的代码才可以,另有一种办法就是在类路径根目录下放置配置文件

jndi.properties,文件代码清单如下:

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory

java.naming.provider.url=jnp://localhost

此时也可以直接编写代码:Context ctx = new IntialContext();来创建初始化上下文。

 

2.创建上下文(类似于创建目录)。代码如下:

ctx.createSubcontext("jdbc");//这相当于在C 盘创建了个子目录

如需创建多层目录结构,那么还可以继续这样创建:

ctx.createSubcontext("jdbc/mysql");

结构相当于下列层次结构:

/jdbc/mysql/

。既然有创建上下文,自然也就有删除上下文,对应的代码是:

ctx.destroySubcontext("jdbc/mysql");

注意:目前JBoss 并不支持这一销毁的操作,调用会报错:not supported

 

3.绑定对象。因为对象不能凭空产生,需要服务器或者用户创建后,然后绑定到服务器

(相当于上传文件到服务器上),之后才能被访问和使用。JBoss 绑定也是这样做的, 它会

启动时首先创建EJB 等对象,然后绑定 EJB 等资源。被绑定的类唯一的要求就是实现

java.io.Serializable 接口。示意代码如下:

ctx.rebind("jdbc/MyName", "BeanSoft 刘长炯");// 我们可以绑定一个数据源对象等其它可序列化的对象

还有一个方法名为bind(),其主要区别是rebind()可以重复绑定(或者说更新老对象),而

bind()只能调用一次。

 

4.查找对象。这一步相当于从服务器下载文件,或者说读取文件,代码如下所示:

// 查找 JNDI 上的对象,

Object myName = ctx.lookup("jdbc/MyName");

// 打印读取的值

System.out.println(myName);

 

5.从服务器删除对象。这一步的操作叫unbind,取消绑定,相当于从服务器上删除文

件,后果就是服务器上指定位置的对象被删掉,不能再次访问到。代码如下:

ctx.unbind("jdbc/MyName");

6.关闭上下文。这一步相当于断开到服务器的连接,注意数据仍然在服务器上存在,可

以在下次连接时再次取到。即使服务器关闭了,这些数据也应该可以通过下次启动时加载。

ctx.close();// 关闭

 

    1.2 如何查看 JBoss 服务器的JNDI

 

首先自然是需要启动 JBoss 服务器了,单独启动或者在MyEclipse 中启动均可,然后

用任意浏览器打开地址:

http://localhost:8080/jmx-console/HtmlAdaptor,这一步将打开JBoss的控制台,然后找到

页面中的下列内容:

 

jboss

database=localDB,service=Hypersonic

name=PropertyEditorManager,type=Service

name=SystemProperties,type=Service

readonly=true,service=invoker,target=Naming,type=http

service=AttributePersistenceService

service=ClientUserTransaction

service=JNDIView

点击链接 service=JNDIView,打开如下地址:

http://localhost:8080/jmx-console/HtmlAdaptor?action=inspectMBean&name=jboss%3As

ervice%3DJNDIView,此时即可看到JBossJNDI的管理Bean,再找到页面中的List of

MBean operations:一栏,如图16.21 所示,点击Invoke按钮后即可看到JNDI列表了。

 

JBoss JNDI 大致分为三类。第一类是各个应用自带的局部JNDI , 例如

JBossWS.war

java:comp namespace of the JBossWS.war application:

 

第二类是服务器提供的服务资源,例如数据源,事务管理器等等,这些内容只能通过

服务器配置,用户不可自行添加和修改,而且只能在服务器内部访问,不可远程访问(例如

可以在同一服务器的JSP 或者EJB 中访问,严格的说不能跨JVM 或者跨网访问)。

java: Namespace

+- XAConnectionFactory (class: org.jboss.mq.SpyXAConnectionFactory)

+- DefaultDS (class: org.jboss.resource.adapter.jdbc.WrapperDataSource)

+- SecurityProxyFactory (class: org.jboss.security.SubjectSecurityProxyFactory)

+- DefaultJMSProvider (class: org.jboss.jms.jndi.JNDIProviderAdapter)

+- comp (class: javax.naming.Context)

这些对象位于java:下的命名空间中,例如下面的数据源DefaultDS 可以这样访问:

访问的时候代码应该这样写:lookup(“java:/DefaultDS”) 或者lookup(“java:DefaultDS”) ;

 

第三类是服务器提供的全局JNDI 资源,这些内容包括各种EJBJMS 服务等等,用

户可以向其中加入自己的JNDI 内容。我们开发的EJB JNDI 测试都位于这下面,例如:

Global JNDI Namespace

+- TopicConnectionFactory (class: org.jboss.naming.LinkRefPair)

 

       1.3 JNDI客户端开发实例

实例一:

1. JBoss JNDI 加入简单对象和自己的对象;

2. JSP 中访问JNDI

3. 使用接口的方式访问JNDI

首先让我们创建一个普通的Java 项目,名为JBossJNDITest,接着,请读者将文件

$JBOSS_HOME/client/jbossall-client.jar(文件大小4.7MB,包含了所有的远程访问

JBoss 服务所需的Java 类库)在Libraries 中通过Add External Jar 加入到项目的 BuildPath(相当于 CLASSPATH) 中,或者将其复制到项目目录中,然后点击右键加入BuildPath

 

package jndi;

 

import java.util.Hashtable;

 

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.naming.NamingException;

 

public class JNDIBindTest {

    InitialContext ctx ; //初始化Context对象

    // 初始化上下文对象

    void initJNDI() throws NamingException{

       Hashtable properties = new Hashtable();

       //配置驱动程序,JBoss特定

        properties.put(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory");

       properties.put(Context.PROVIDER_URL, "jnp://localhost");

       ctx = new InitialContext(properties);

    }

   

    //关闭JNDI

    void closeJNDI() throws NamingException{

       ctx.close();

    }

   

    //创建层次结构

    void createContext() throws NamingException{

       ctx.createSubcontext("liangbinny");  //先创建liangbinny层,才能创建其下面的子层次,相当于文件夹

       ctx.createSubcontext("liangbinny/stringtest");

    }

   

    //删除层次结构

    void deleteContext() throws NamingException{

       ctx.destroySubcontext("liangbinny/stringtest");  //先删除子层次,再删除上一层次,相当于先删除子文件夹,然后再删除上一级文件夹

       ctx.destroySubcontext("liangbinny");

    }

   

    //绑定字符串

    void bindString() throws NamingException{

       ctx.rebind("liangbinny/stringtest/MyName", "wenbin");  //bind只绑定一次,rebind可绑定多次

    }

   

    void lookupString() throws NamingException{

       Object myName = ctx.lookup("liangbinny/stringtest/MyName");

       System.out.println(myName);

    }

   

    // 取消 JNDI 绑定, 相当于删除文件

    void unbindString() throws NamingException{

       ctx.unbind("liangbinny/stringtest/MyName");

    }

   

    void stringTest() throws NamingException{

       initJNDI();

       createContext();

       bindString();

       lookupString();

    //  unbindString();

    //  deleteContext();

       closeJNDI();

    }

   

    public JNDIBindTest(){

       try {

           stringTest();

       } catch (Exception e) {

           e.printStackTrace();

       }

    }

   

    public static void main(String[] args) {

       new JNDIBindTest();

    }

}

 

,这段内容是从lookupString()这个方法中执行得到的。然而,此时我们查看JBoss JNDI

树,会看到全局JNDI 下面多出了下面所示的内容:

http://localhost:8080/jmx-console/HtmlAdaptor

 

 

。那么从此以后,这个对象就放在了JBoss 服务器上了,但是如果只是这样存放的数据,

关闭服务器后下次再打开,它们就消失了,具体错误为:

javax.naming.NameNotFoundException:liangbinny not bound(一般来说JBoss 是通过配置文件的方式来确保每次启动时都会绑定对象)。不过,在本次服务器未重启时,数据是一直可以看到的,那么第二次运行测试代码访问时,就不需要再次绑定数据就可以读取到了,此时的测试方法应修改为:

void stringTest() throws NamingException {

initJNDI();

lookupString();

closeJNDI();

}

读者可以试试第二次运行,采用这样的几个方法,包括打开,读取和关闭,同样可以读到数

据。

 

 

实例一:

保持上面服务器存放数据不变的情况下,从 Web 程序中访问JNDI 数据,很简单,创建一个Web 项目名为JBossJNDIWeb,然后修改其index.jsp 文件内容为:

 

<%@ page language="java" pageEncoding="GBK"%>

<%@page import="javax.naming.InitialContext"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <title>JNDI Web 访问测试</title>

  </head>

 

  <body>

    <%

    InitialContext ctx = new InitialContext();

    Object name = ctx.lookup("liangbinny/stringtest/MyName");  //不需要创建上下文就可以访问了,因为JBoss下面现在已经有这个上下文了。

    out.println(name);

     %>

  </body>

</html>

 

。此处没有设置上下文参数就可创建InitialContext 是因为默认在JBoss 中它连向JBoss

带的JNDI 服务,Context 工厂类采用JBoss 自带值,URL 则指向当前所在的JSP 程序所

在服务器。反过来如果需要连接到别的服务器,或者是用Tomcat 来作为客户端访问远程的

JNDI 数据,就需要采用那种设置初始化参数的方式了。

 

最后,我们要测试的是这样一种场景。假设我们和一家客户通过JNDI 提供服务,我们

编写了一个接口,告诉他们提供了什么样的服务,但是,我们不希望他们知道我们的核心技

术,在这种情况下,自然不能给他们实现类的源代码了(再次只能模拟EJB+客户端的一

种情况)。那么客户只需要拿到接口和JNDI 的地址,就可以调用此服务了,而类的源代码

它们是拿不到的,那么,我们分两部分来开发。首先看提供服务的人,我们,需要开发一个

接口和一个类,这个服务假设就是做汇率计算,从美元转换成人民币。继续刚才开发的项目

JBossJNDITest,新建两个类。

接口 bean.Calculator 代码清单如下:

 

package bean;

 

public interface Calculator {

   

    double dollarToRMB(double input);

   

}

 

 

package bean;

 

import java.io.Serializable;

 

public class CalculatorImpl implements Calculator,Serializable{

 

    public CalculatorImpl() {

    }

 

    public double dollarToRMB(double input) {

       return input * 7.0026;

    }

 

}

 

 

<%@ page language="java" pageEncoding="GBK"%>

<%@page import="javax.naming.InitialContext"%>

<%@page import="bean.CalculatorImpl"%>

<%@page import="bean.Calculator"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <title>JNDI Web 访问测试</title>

  </head>

 

  <body>

    <%

    InitialContext ctx = new InitialContext();

    Calculator calc = (Calculator)ctx.lookup("Calculator/remote");  //不需要创建上下文就可以访问了,因为JBoss下面现在已经有这个上下文了。

    out.println(calc.dollarToRMB(1.23));

     %>

  </body>

</html>

 

随 后 , 发 布 应 用 到 JBoss 服务器后,在浏览器中键入地址

http://localhost:8080/JBossJNDIWeb/calculator.jsp 即可测试,输出的结果应是:

8.613198

。读者需要注意上面的代码形式,可以看到JNDI 时可以完全不用关心实现类的名字,只需

要转换为接口即可。而JNDI 的对象地址Calculator/remote 实际上是我们自己通过JNDI

提供的创建Context 功能和绑定功能完成的,实际上JBoss 发布EJB 时,也会采用类似的

调用过程,本节内容就是为了帮助大家理解即将出现的JBoss EJB 客户端代码的访问方式

的。

 

1.4 JNDI 访问数据源

 

1、 找到JBoss 的安装目录下的docs/examples/jca 中找到配置文件oracle -ds,将其内容修改为如下所示:

 

<?xml version="1.0" encoding="UTF-8"?>

 

<!-- ===================================================================== -->

<!--                                                                       -->

<!--  JBoss Server Configuration                                           -->

<!--                                                                       -->

<!-- ===================================================================== -->

 

<!-- $Id: oracle-ds.xml 63175 2007-05-21 16:26:06Z rrajesh $ -->

<!-- ==================================================================== -->

<!--  Datasource config for Oracle originally from Steven Coy             -->

<!-- ==================================================================== -->

 

 

<datasources>

  <local-tx-datasource>

    <jndi-name>OracleDS</jndi-name>+

    <use-java-context>false</use-java-context>

    <connection-url>jdbc:oracle:thin:@10.200.25.151:1521:boss20dev</connection-url>

       <!--

 

              Here are a couple of the possible OCI configurations.

              For more information, see http://otn.oracle.com/docs/products/oracle9i/doc_library/release2/java.920/a96654/toc.htm

 

       <connection-url>jdbc:oracle:oci:@youroracle-tns-name</connection-url>

              or

<connection-url>jdbc:oracle:oci:@(description=(address=(host=youroraclehost)(protocol=tcp)(port=1521))(connect_data=(SERVICE_NAME=yourservicename)))</connection-url>

 

              Clearly, its better to have TNS set up properly.

        -->

    <driver-class>oracle.jdbc.driver.OracleDriver</driver-class>

    <user-name>common</user-name>

    <password>common</password>

    <!-- Uses the pingDatabase method to check a connection is still valid before handing it out from the pool -->

    <!--valid-connection-checker-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleValidConnectionChecker</valid-connection-checker-class-name-->

    <!-- Checks the Oracle error codes and messages for fatal errors -->

    <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name>

        <!-- sql to call when connection is created

        <new-connection-sql>some arbitrary sql</new-connection-sql>

        -->

 

        <!-- sql to call on an existing pooled connection when it is obtained from pool - the OracleValidConnectionChecker is prefered

        <check-valid-connection-sql>some arbitrary sql</check-valid-connection-sql>

        -->

 

      <!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml -->

      <metadata>

         <type-mapping>Oracle9i</type-mapping>

      </metadata>

  </local-tx-datasource>

 

</datasources>

 

启动对应的数据库,然后将oracle的驱动class12.jar包加入到%jboss%/server/default/lib下,并将该配置文件放置%jboss%/server/default/deploy下,启动Jboss,后台可以看到如图输出,Bound ConnectionManager 'jboss.jca:service=DataSourceBinding,name=OracleDS' to JNDI name 'OracleDS'

表示数据源绑定成功。

 

,这样即是将数据源发布了,查看JBoss JNDI 的话,位于Global JNDI Namespace 下。

注意:默认情况下,JBoss 的数据源都是配置为仅服务器可见的(即服务器内部的EJB

JSP 应用能够访问,外部例如独立运行的Java 程序客户端不能访问),也就是位于

JavaNamespace 下面。如果要做跨服务器的测试, 请加入标签

<use-java-context>false</use-java-context>,例如我们的例子所示。一般情况下如果没

有远程访问数据源的要求,则可以去掉此配置,就像JBoss 自带的数据源java:DefaultDS

一样。

   

    加入了<use-java-context>false</use-java-context>这个标记,就是全局的,去掉此配置,则变为了JBoss自带的数据源一样,本机可以访问。

 

2、 测试数据源

 

Java 项目JBossJNDITest src 目录下新建文件

jndi.properties,代码清单如下:

 

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory

java.naming.provider.url=jnp://localhost

 

这样,我们在代码中

InitialContext ctx = new InitialContext();

就已经初始化上下文了。不用再初始化了。

由于使用了JNDI 配置文件,所以初始化上下文的时候,就不需要再设置参数了,这是个节

省代码的好办法,推荐在普通Java 类中访问JNDI 时使用。这段代码运行后,输出内容如

下:

org.jboss.invocation.jrmp.interfaces.JRMPInvokerProxy@e102dc

Lee

CXY

 

 

即输出了表的用户名内容。

 

 

 

接着我们展示位于java:下面的服务器私有的数据源的访问方式,它们只能通过在同一

服务器上的JSP 或者EJB 来访问,所以在Web 项目JBossJNDIWeb WebRoot 下新建

JSP 文件datasource.jsp,代码清单如下:

<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>

<%@page import="javax.naming.InitialContext"%>

<%@page import="javax.sql.DataSource"%>

<%@page import="java.sql.Connection"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <title>JNDI 私有数据源 访问测试</title>

  </head>

 

  <body>

   <%

        InitialContext ctx = new InitialContext();

        Object obj = ctx.lookup("java:DefaultDS");

        DataSource ds = (DataSource) obj;

       Connection conn = ds.getConnection();

       out.println(conn.getMetaData().getDatabaseProductName());

       conn.close();

       ctx.close();

    %>

  </body>

</html>

 

运行,输出

 

这说明JBoss默认的这个DefaultDS数据源,是HSQL,也是个开源的嵌入式Java数据库,

其官方网站地址是http://www.hsqldb.org/

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值