您的位置:首页 > 运维架构 > Tomcat

JNDI初探之tomcat的datasource配置

2016-04-14 14:10 281 查看
有人说:没有掌握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技术产生后,就可方便的查找远程或是本地对象。



许多开发人员知道:代码和外部资源之间的紧密耦合是潜在的问题,但是在实践中却经常忘记角色的划分。在小型开发工作中(指的是团队规模或部署规模),即使忽视角色划分也能获得成功。

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 的承诺,而且经过一些计划和预先考虑,这个承诺是完全可以实现的。实际上,它要比许多人想像的容易得多。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: