JNDI初探之tomcat的datasource配置

有人说:没有掌握JNDI就没有真正的理解JavaEE。
看来我一直都没理解呀!

JavaEE 的角色

在聊JNDI之前,我们先讨论一下JavaEE的角色吧。
J2EE 规范把职责委托给多个开发角色:组件提供者(Component Provider)、应用程序组装者(Application Assembler)、部署人员(Deployer)和系统管理员(System Administrator)。

组件提供者 这个角色负责创建 J2EE 组件,J2EE 组件可以是 Web 应用程序、企业级
JavaBean(EJB)组件,或者是应用程序客户机(例如基于 Swing 的 GUI 客户机应用程序)。组件提供者包括:HTML
设计师、文档编程人员以及其他开发人员角色。大多数 J2EE 开发人员在组件提供者这一角色上耗费了相当多的时间。 应用程序组装者
这个角色将多个 J2EE
模块捆绑成一个彼此结合的、可以部署的整体:企业归档(EAR)文件。应用程序组装者要选择组件,分清它们之间的交互方式,配置它们的安全性和事务属性,并把应用程序打包到
EAR 文件中。许多 IDE,例如 WebSphere® Studio、IDEA、JBuilder、WebLogic Workshop
和其他 IDE,都可以帮助应用程序组装者以交互方式配置 EAR 文件。 部署人员(Deployer) 这个角色负责部署,这意味着将 EAR
安装到 J2EE
容器(应用服务器)中,然后配置资源(例如数据库连接池),把应用程序需要的资源绑定到应用服务器中的特定资源上,并启动应用程序。
系统管理员(System Administrator) 这个角色负责保证容器需要的资源可用于容器。

外部资源的后绑定

任何不平凡(nontrivial)的 J2EE 应用程序都需要访问描述它期望使用环境的信息。这意味着开发和测试组件时,为了临时测试代码,开发人员要承担一些部署方面的职责。重要的是要理解:这么做的时候,您就走出了开发人员的领域。否则,可以试着依靠 JDBC 驱动程序,或 URL、JMS 队列名称,或者其他具有无意识的、偶尔可能是灾难性暗示的机器资源。

什么是JNDI

命名和目录接口,Java Naming and Directory Interface。
为什么会有jndi?
jndi诞生的理由似乎很简单。随着分布式应用的发展,远程访问对象访问成为常用的方法。虽然说通过 Socket等编程手段仍然可实现远程通信,但按照模式的理论来说,仍是有其局限性的。RMI技术,RMI-IIOP技术的产生,使远程对象的查找成为了技术焦点。JNDI技术就应运而生。JNDI技术产生后,就可方便的查找远程或是本地对象。
JNDI初探之tomcat的datasource配置_第1张图片
许多开发人员知道:代码和外部资源之间的紧密耦合是潜在的问题,但是在实践中却经常忘记角色的划分。在小型开发工作中(指的是团队规模或部署规模),即使忽视角色划分也能获得成功。
J2EE 规范要求所有 J2EE 容器都要提供 JNDI 规范的实现。JNDI 在 J2EE 中的角色就是“交换机” —— J2EE 组件在运行时间接地查找其他组件、资源或服务的通用机制。在多数情况下,提供 JNDI 供应者的容器可以充当有限的数据存储,这样管理员就可以设置应用程序的执行属性,并让其他应用程序引用这些属性(Java 管理扩展(Java Management Extensions,JMX)也可以用作这个目的)。JNDI 在 J2EE 应用程序中的主要角色就是提供间接层,这样组件就可以发现所需要的资源,而不用了解这些间接性。

举个例子

典型的数据源配置,我就不举例子了,你肯定知道。
那,怎么用JNDI来配置呢?让开发和部署分隔开。
以tomcat为例:

server.xml

<GlobalNamingResources>
    <!-- Editable user database that can also be used by UserDatabaseRealm to authenticate users -->
    <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" />
    <Resource name="jdbc/mysql" scope="Shareable" type="javax.sql.DataSource" factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory" url="jdbc:mysql://localhost:3306/armstrong" driverClassName ="com.mysql.jdbc.Driver" username="root" password="nington" />  
    <Resource name="jdbc/mysql_c3p0" scope="Shareable" type="com.mchange.v2.c3p0.ComboPooledDataSource" factory="org.apache.naming.factory.BeanFactory" jdbcUrl="jdbc:mysql://localhost:3306/armstrong" driverClass="com.mysql.jdbc.Driver" user="root" password="nington" />
  </GlobalNamingResources>

context.xml

<Context>
    <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource> 
    <ResourceLink global="jdbc/mysql_c3p0" name="jdbc/mysql" type="javax.sql.DataSource" />  
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>

spring.xml

 <!--<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"-->
          <!--destroy-method="close">-->
        <!--<property name="driverClass" value="${app.db.driver}"/>-->
        <!--<property name="jdbcUrl" value="${app.db.url}"/>-->
        <!--<property name="user" value="${app.db.user}"/>-->
        <!--<property name="password" value="${app.db.password}"/>-->
        <!--<property name="maxPoolSize" value="${app.db.maxPoolSize}"/>-->
        <!--<property name="minPoolSize" value="10"/>-->
        <!--<property name="initialPoolSize" value="10"/>-->
        <!--<property name="maxIdleTime" value="20"/>-->
    <!--</bean>-->

    <jee:jndi-lookup id="dataSource" jndi-name="jdbc/mysql" />

不出问题的话,应该就可以了。当然tomcat还有很多其他配置方式,有兴趣可以查阅相关的资料。

超越数据源

当然,J2EE 中的资源并不局限于 JDBC 数据源。引用的类型有很多,其中包括资源引用(已经讨论过)、环境实体和 EJB 引用。特别是
EJB 引用,它暴露了 JNDI 在 J2EE 中的另外一项关键角色:查找其他应用程序组件。 试想一下这种情况:当一家公司从 Order
Ontology Processing Services(OOPS)购买了一个可部署的 EJB
组件来处理客户订单时,会发生什么。为了便于举例说明,我们把它叫做 ProcessOrders V1.0。ProcessOrders 1.0
有两部分:一组接口和支持类(home 和 remote 接口,以及支持的传输类);实际 EJB 组件自身。选择 OOPS
是因为它在这个领域的专业性。 该公司遵照 J2EE 规范,编写使用 EJB 引用的 Web 应用程序。公司的部署人员把
ProcessOrders 1.0 绑定到 JNDI 树中,将它用作 ejb/ProcessOrders/1.0,并解析 Web
应用程序的资源名称,以指向这个全局 JNDI 名称。目前为止,这些都是 EJB
组件非常普通的用法。但是,当我们考虑公司的开发周期与公司供应商之间的交互时,事情就变得复杂起来。在这里,JNDI 也能帮助我们。 我们假设
OOPS 发布了一个新版本,即 ProcessOrders
V1.1。这个新版本有一些新功能,公司内部的一个新应用程序需要这些新功能,而且很自然地扩展了 EJB 组件的业务接口。
在这里,公司有以下几个选择:可以更新所有应用程序来使用新版本,也可以编写自己的版本,或者使用 JNDI
的引用解析,允许每个应用程序在不影响其他应用程序的情况下使用自己的 EJB
组件版本。立刻更新所有应用程序对维护来说是一场噩梦,它要求对所有组件都进行完整的回归测试,这通常是一项艰巨的任务,而且如果发生任何功能测试失败的话,那么还要进行另一轮调试。
编写内部(in-house)组件常常是没有必要的重复工作。如果组件是由在这个业务领域内具有专业知识的公司编写的,那么给定的 IT
商店不可能像专业的组件供应商那样精通业务功能。 正如您可能已经猜到的那样,最好的解决方案是用 JNDI 解析。EJB 的 JNDI
引用非常类似于 JDBC 资源的引用。对于每个引用,部署人员都需要把新组件按特定的名称(比如说
ejb/ProcessOrders/1.1)绑定到全局树中,对于需要 EJB 组件的其他每个组件,还要为组件在部署描述符中解析 EJB
引用。依赖于 V1.0
以前的应用程序不需要进行任何修改,也不需要重新测试,这缩短了实现的时间、降低了成本并减少了复杂性。在服务趋于转换的环境中,这是一种很有效的方法。可以对应用程序架构中所得到的所有组件进行这类配置管理,从
EJB 组件到 JMS
队列和主题,再到简单配置字符串或其他对象,这可以降低随时间的推移服务变更所产生的维护成本,同时还可以简化部署,减少集成工作。

结束语

有一个古老的计算机科学笑话:每个编程问题都可以仅仅用一个抽象层(或间接的)来解决。在 J2EE 中,JNDI 是把 J2EE 应用程序合在一起的粘合剂,但还没有紧到无法让人很容易地把它们分开并重新装配。JNDI 提供的间接寻址允许跨企业交付可伸缩的、功能强大且很灵活的应用程序。这是 J2EE 的承诺,而且经过一些计划和预先考虑,这个承诺是完全可以实现的。实际上,它要比许多人想像的容易得多。

你可能感兴趣的:(tomcat,JNDI)