您的位置:首页 > 其它

jndi的一点介绍(转)

2009-04-30 21:34 218 查看
没有对 JDBC
驱动程序的引用,没有服务器名称,没有用户名称或口令 —— 甚至没有数据库池或连接管理。Dolly
需要编写代码来忽略将要访问的特定外部资源,只需要知道其他人会提供使用这些外部资源所需的链接即可。这允许部署人员(任何处在这个角色的人)把数据库连
接分配给 Dolly 的应用程序。Dolly 没有必要参与其中。(从数据库安全性到遵守 Sarbanes-Oxley
法案,她都没有参与进来,她这样做也有充足的业务理由。)

许多开发人员知道:代码和外部资源之间的紧密耦合是潜在的问题,但是在实践中却经常忘记角色的划分。在小型开发工作中(指的是团队规模或部署规
模),即使忽视角色划分也能获得成功。(毕竟,如果应用程序只是个人的应用程序,而且您不准备依靠它,那么把应用程序锁定在特定的
PostgreSQL 实例上也挺好的。)

J2EE 规范要求所有 J2EE 容器都要提供 JNDI 规范的实现。JNDI 在 J2EE 中的角色就是“交换机” —— J2EE
组件在运行时间接地查找其他组件、资源或服务的通用机制。在多数情况下,提供 JNDI
供应者的容器可以充当有限的数据存储,这样管理员就可以设置应用程序的执行属性,并让其他应用程序引用这些属性(Java 管理扩展(Java
Management Extensions,JMX)也可以用作这个目的)。JNDI 在 J2EE
应用程序中的主要角色就是提供间接层,这样组件就可以发现所需要的资源,而不用了解这些间接性。

现在我们重新来看一下 Dolly 的情况。在其简单的 Web 应用程序中,她直接从应用程序代码中使用了一个 JDBC 连接。参见清单
1,我们可以看出,Dolly 显式地把 JDBC 驱动程序、数据库 URL 以及她的用户名和口令编码到了 servlet 中:

清单 1. 典型(但是不好)的 JDBC 用法

Connection conn=null;
try {
Class.forName("com.mysql.jdbc.Driver",
true, Thread.currentThread().getContextClassLoader());
conn=DriverManager.getConnection("jdbc:mysql://dbserver?user=dolly&password=dagger");
/* use the connection here */
c.close();
}
catch(Exception e) {
e.printStackTrace();
}
finally {
if(conn!=null) {
try {
conn.close();
} catch(SQLException e) {}
}
}

如果不用这种方式指定配置信息,Dolly(以及她的同伴们)使用 JNDI 来查找 JDBC
DataSource
会更好一些,如清单 2 所示:

清单 2. 使用 JNDI 得到数据源

Connection conn=null;
try {
Context ctx=new InitialContext();
Object datasourceRef=ctx.lookup("java:comp/env/jdbc/mydatasource");
DataSource ds=(Datasource)datasourceRef;
Connection c=ds.getConnection();
/* use the connection */
c.close();
}
catch(Exception e) {
e.printStackTrace();
}
finally {
if(conn!=null) {
try {
conn.close();
} catch(SQLException e) { }
}
}

为了能够得到 JDBC 连接,首先要执行一些小的部署配置,这样我们才可以在本地组件的 JNDI 下文中查找
DataSource
。这可能有点烦琐,但是很容易学。不幸的是,这意味着即使是为了测试组件,开发人员也必须涉足部署人员的领地,并且还要准备配置应用服务器。

配置 JNDI 引用

为了让 JNDI 解析
java:comp/env/jdbc/mydatasource
引用,部署人员必须把
<resource-ref>
标签插入 web.xml 文件(Web 应用程序的部署描述符)。
<resource-ref>
标签的意思就是“这个组件依赖于外部资源”。清单 3 显示了一个示例:

清单 3. resource-ref 入口

<resource-ref>
<description>Dollys DataSource</description>
<res-ref-name>jdbc/mydatasource</res-ref-name>
<res-ref-type>javax.sql.DataSource</res-ref-type>
<res-auth>Container</res-auth>
</resource-ref>

<resource-ref>
入口告诉 servlet 容器,部署人员要在 组件命名上下文(component naming context) 中设置一个叫做
jdbc/mydatasource
的资源。组件命名上下文由前缀
java:comp/env/
表示,所以完全限定的本地资源名称是:
java:comp/env/jdbc/mydatasource
.

这只定义了到外部资源的本地引用,还没有创建引用指向的实际资源。(在 Java 语言中,类似的情况可能是:
<resource-ref>
声明了一个引用,比如
Object foo
,但是没有把
foo
设置成实际引用任何
Object
。)

部署人员的工作就是创建
DataSource
(或者是创建一个
Object
对象,让
foo

指向它,在我们的 Java 语言示例中就是这样)。每个容器都有自己设置数据源的机制。例如,在 JBoss 中,是利用服务来定义数据源(请参阅
$JBOSS/server/default/deploy/hsqldb-ds.xml,把它作为示例),它指定自己是
DataSource
的全局 JNDI 名称(默认情况下是
DefaultDS
)。在创建资源之后,第三步仍然很关键:把资源连接或者绑定到应用程序组件使用的本地名称。在使用 Web 应用程序的情况下,是使用特定于供应商的部署描述符扩展来指定这个绑定,清单 4 中显示了一个这样的例子。(JBoss 用称为
jboss-Web.xml
的文件作为特定于供应商的 Web 应用程序部署描述符。)

清单 4. 用特定于供应商的部署描述符将资源绑定到 JDI 名称

<resource-ref>
<res-ref-name>jdbc/mydatasource</res-ref-name>
<jndi-name>java:DefaultDS</jndi-name>
</resource-ref>

这表明应该将本地资源引用名称(
jdbc/mydatasource
)映射到名为
java:DefaultDS
的全局资源。如果全局资源名称出于某种原因发生了变化,而应用程序的代码无需变化,那么只需修改这个映射即可。在这里,有两个级别的间接寻址:一个定义并命名资源(
java:DefaultDS
),另一个把特定于本地组件的名称(
jdbc/mydatasource
)绑定到命名的资源。(实际上,当您在 EAR 级别上映射资源时,可能还存在第三级别的间接寻址。)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: