什么是JNDI?為什么使用JNDI?
JNDI是Java 命名與目錄接口(Java Naming and Directory Interface)
要了解JNDI的作用,我們可以從“如果不用JNDI我們怎樣做?用了JNDI后我們又將怎樣做?”這個(gè)問題來探討。
沒有JNDI的做法:
程序員開發(fā)時(shí),知道要開發(fā)訪問MySQL數(shù)據(jù)庫的應(yīng)用,于是將一個(gè)對 MySQL JDBC 驅(qū)動程序類的引用進(jìn)行了編碼,并通過使用適當(dāng)?shù)?JDBC URL 連接到數(shù)據(jù)庫。
就像以下代碼這樣:
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并進(jìn)行SQL操作 */ conn.close();
} catch(Exception e) {
e.printStackTrace();
} finally {
if(conn!=null) {
try { conn.close();
} catch(SQLException e) {
}
}}
這是傳統(tǒng)的做法,這種做法一般在小規(guī)模的開發(fā)過程中不會產(chǎn)生問題,只要程序員熟悉Java語言、了解JDBC技術(shù)和MySQL,可以很快開發(fā)出相應(yīng)的應(yīng)用程序。
沒有JNDI的做法存在的問題:
1、數(shù)據(jù)庫服務(wù)器名稱MyDBServer 、用戶名和口令都可能需要改變,由此引發(fā)JDBC URL需要修改;
2、數(shù)據(jù)庫可能改用別的產(chǎn)品,如改用DB2或者Oracle,引發(fā)JDBC驅(qū)動程序包和類名需要修改;
3、隨著實(shí)際使用終端的增加,原配置的連接池參數(shù)可能需要調(diào)整;
4、......
解決辦法:
程序員應(yīng)該不需要關(guān)心“具體的數(shù)據(jù)庫后臺是什么?JDBC驅(qū)動程序是什么?JDBC URL格式是什么?訪問數(shù)據(jù)庫的用戶名和口令是什么?”等等這些問題,程序員編寫的程序應(yīng)該沒有對 JDBC 驅(qū)動程序的引用,沒有服務(wù)器名稱,沒有用戶名稱或口令 —— 甚至沒有數(shù)據(jù)庫池或連接管理。而是把這些問題交給J2EE容器來配置和管理,程序員只需要對這些配置和管理進(jìn)行引用即可。
由此,就有了JNDI。
用了JNDI之后的做法:
首先,在在J2EE容器中配置JNDI參數(shù),定義一個(gè)數(shù)據(jù)源,也就是JDBC引用參數(shù),給這個(gè)數(shù)據(jù)源設(shè)置一個(gè)名稱;然后,在程序中,通過數(shù)據(jù)源名稱引用數(shù)據(jù)源從而訪問后臺數(shù)據(jù)庫。
具體操作如下(以JBoss為例):
1、配置數(shù)據(jù)源
在JBoss的 D:\jboss420GA\docs\examples\jca 文件夾下面,有很多不同數(shù)據(jù)庫引用的數(shù)據(jù)源定義模板。將其中的 mysql-ds.xml 文件Copy到你使用的服務(wù)器下,如 D:\jboss420GA\server\default\deploy。
修改 mysql-ds.xml 文件的內(nèi)容,使之能通過JDBC正確訪問你的MySQL數(shù)據(jù)庫,如下:
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>MySqlDS</jndi-name>
<connection-url>jdbc:mysql://localhost:3306/lw</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>root</user-name>
<password>rootpassword</password>
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>
這里,定義了一個(gè)名為MySqlDS的數(shù)據(jù)源,其參數(shù)包括JDBC的URL,驅(qū)動類名,用戶名及密碼等。
2、在程序中引用數(shù)據(jù)源:
Connection conn=null;
try {
Context ctx=new InitialContext();
Object datasourceRef=ctx.lookup("java:MySqlDS"); //引用數(shù)據(jù)源
DataSource ds=(Datasource)datasourceRef; conn=ds.getConnection(); /* 使用conn進(jìn)行數(shù)據(jù)庫SQL操作 */
......
c.close();
} catch(Exception e) {
e.printStackTrace();
} finally { if(conn!=null) {
try {
conn.close();
} catch(SQLException e) { } }}
直接使用JDBC或者通過JNDI引用數(shù)據(jù)源的編程代碼量相差無幾,但是現(xiàn)在的程序可以不用關(guān)心具體JDBC參數(shù)了。
在系統(tǒng)部署后,如果數(shù)據(jù)庫的相關(guān)參數(shù)變更,只需要重新配置 mysql-ds.xml 修改其中的JDBC參數(shù),只要保證數(shù)據(jù)源的名稱不變,那么程序源代碼就無需修改。
由此可見,JNDI避免了程序與數(shù)據(jù)庫之間的緊耦合,使應(yīng)用更加易于配置、易于部署。
所以,在J2EE規(guī)范中,J2EE 中的資源并不局限于 JDBC 數(shù)據(jù)源。引用的類型有很多,其中包括資源引用(已經(jīng)討論過)、環(huán)境實(shí)體和 EJB 引用。特別是 EJB 引用,它暴露了 JNDI 在 J2EE 中的另外一項(xiàng)關(guān)鍵角色:查找其他應(yīng)用程序組件。
JNDI原理
sun只是提供了JNDI的接口(即規(guī)范),IBM, Novell, Sun 和 WebLogic 和JBOSS已經(jīng)為 JNDI 提供了服務(wù)提供程序,
在JNDI中,在目錄結(jié)構(gòu)中的每一個(gè)結(jié)點(diǎn)稱為context。每一個(gè)JNDI名字都是相對于context的。這里沒有絕對名字的概念存在。對一個(gè)應(yīng)用來說,它可以通過使用 InitialContext 類來得到其第一個(gè)context:
Context ctx = new InitialContext();
ctx.bind("name", Object);
ctx.lookup("name");
Context:上下文,我的理解是相當(dāng)與文件系統(tǒng)的中的目錄(JNDI的Naming Service是可以用操作系統(tǒng)的文件系統(tǒng)的,哈哈).
entry/object:一個(gè)節(jié)點(diǎn),相當(dāng)與文件系統(tǒng)中的目錄或文件.
filter:查詢/過濾條件是一個(gè)字符串表達(dá)式如:(&(objectClass=top)(cn=*))查詢出objectClass屬性為top,cn屬性為所有情況的entry.
Attribute:entry/object的屬性可以理解成JAVA對象的屬性,不同的是這個(gè)屬性可以多次賦值.
A.將接口分為Context 和 DirContext
JNDI有兩個(gè)核心接口Context和DirContext,Context中包含 了基本的名字操作,而DirContext則將這些操作擴(kuò)展到目錄服務(wù)。DirContext 對Context進(jìn)行了擴(kuò)展,提供了基本的目錄服務(wù)操作, 對名字對象屬性的維護(hù)、基于屬性的名字查找等等。
B.上下文列表的多種方法
一般來說有兩種進(jìn)行上下文列表的應(yīng)用:上下文瀏覽應(yīng)用和對上下文中的對象進(jìn)行實(shí)際操作的應(yīng)用。
上下文瀏覽應(yīng)用一般只需要顯示上下文中包含內(nèi)容的名字,或者再獲取一些諸如對象的類型之類的信息。這種類型的應(yīng)用一般都是交互式的,可以允許用戶在列舉的上下文列表中選擇一些進(jìn)行進(jìn)一步的顯示。
另外有一些應(yīng)用需要對上下文中的對象進(jìn)行實(shí)際的操作,比如,一個(gè)備份程序需要對目錄中所有文件的狀態(tài)進(jìn)行操作,或者某打印機(jī)管理員可能需要對大樓中的所有打印機(jī)進(jìn)行復(fù)位。為了進(jìn)行這樣的操作,程序需要獲取上下文中的實(shí)際對象。
對于這樣兩種類型的應(yīng)用,Context接口提供了兩種上下文列表方法list()和 listBindings()。其中l(wèi)ist()只返回一系列名字/類映射,而listBindings() 則返回名字、類和對象本身。顯然 list()用于上下文瀏覽應(yīng)用而listBindings()用于那些需要對對象進(jìn)行實(shí)際操作的應(yīng)用。
例:
=================將以下代碼段添加到server.xml中的<Host>中============
<!-- configure DataSource. Add the following code into server.xml -->
<Context path="/bookstore" docBase="bookstore" debug="0"
reloadable="true" >
<!-- 數(shù)據(jù)源名稱 -->
<Resource name="jdbc/BookDB"
auth="Container"
type="javax.sql.DataSource" />
<ResourceParams name="jdbc/BookDB">
<parameter>
<name>factory</name>
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
</parameter>
<!-- Maximum number of dB connections in pool. Make sure you
configure your mysqld max_connections large enough to handle
all of your db connections. Set to 0 for no limit.
-->
<!-- 活動狀態(tài)最大連接數(shù) -->
<parameter>
<name>maxActive</name>
<value>100</value>
</parameter>
<!-- Maximum number of idle dB connections to retain in pool.
Set to 0 for no limit.
-->
<!-- 空閑狀態(tài)數(shù)據(jù)庫連接最大數(shù) -->
<parameter>
<name>maxIdle</name>
<value>30</value>
</parameter>
<!-- Maximum time to wait for a dB connection to become available
in ms, in this example 10 seconds. An Exception is thrown if
this timeout is exceeded. Set to -1 to wait indefinitely.
Maximum time to wait for a dB connection to become available
in ms, in this example 10 seconds. An Exception is thrown if
this timeout is exceeded. Set to -1 to wait indefinitely.
-->
<!-- 數(shù)據(jù)庫處于空閑狀態(tài)的最長時(shí)間 -->
<parameter>
<name>maxWait</name>
<value>10000</value>
</parameter>
<!-- MySQL dB username and password for dB connections -->
<!-- 指定連接數(shù)據(jù)庫的用戶名及密碼 -->
<parameter>
<name>username</name>
<value>dbuser</value>
</parameter>
<parameter>
<name>password</name>
<value>1234</value>
</parameter>
<!-- Class name for mm.mysql JDBC driver -->
<!-- 指定JDBC驅(qū)動 -->
<parameter>
<name>driverClassName</name>
<value>com.mysql.jdbc.Driver</value>
</parameter>
<!-- The JDBC connection url for connecting to your MySQL dB.
The autoReconnect=true argument to the url makes sure that the
mm.mysql JDBC Driver will automatically reconnect if mysqld closed the
connection. mysqld by default closes idle connections after 8 hours.
-->
<!-- 指定連接數(shù)據(jù)庫的URL -->
<parameter>
<name>url</name>
<value>jdbc:mysql://localhost:3306/BookDB?autoReconnect=true</value>
</parameter>
</ResourceParams>
</Context>
運(yùn)行機(jī)制:
1、 首先程序代碼獲取初始化的 JNDI 環(huán)境并且調(diào)用 Context.lookup() 方法從 JNDI 服務(wù)提供者那里獲一個(gè) DataSource 對象
2、 中間層 JNDI 服務(wù)提供者返回一個(gè) DataSource 對象給當(dāng)前的 Java 應(yīng)用程序這個(gè) DataSource 對象代表了中間層服務(wù)上現(xiàn)存的緩沖數(shù)據(jù)源
3、 應(yīng)用程序調(diào)用 DataSource 對象的 getConnection() 方法
4、 當(dāng) DataSource 對象的 getConnection() 方法被調(diào)用時(shí),中間層服務(wù)器將查詢數(shù)據(jù)庫 連接緩沖池中有沒有 PooledConnection 接口的實(shí)例對象。這個(gè) PooledConnection 對象將被用于與數(shù)據(jù)庫建立物理上的數(shù)據(jù)庫連接
5、 如果在緩沖池中命中了一個(gè) PooledCoonection 對象那么連接緩沖池將簡單地更 新內(nèi)部的緩沖連接隊(duì)列并將該 PooledConnection 對象返回。如果在緩沖池內(nèi)沒 有找到現(xiàn)成的 PooledConnection 對象,那么 ConnectionPoolDataSource 接口將會被 用來產(chǎn)生一個(gè)新的 PooledConnection 對象并將它返回以便應(yīng)用程序使用
6。 中間層服務(wù)器調(diào)用 PooledConnection 對象的 getConnection() 方法以便返還一個(gè) java.sql.Connection 對象給當(dāng)前的 Java 應(yīng)用程序
7、 當(dāng)中間層服務(wù)器調(diào)用 PooledConnection 對象的 getConnection() 方法時(shí), JDBC 數(shù)據(jù) 庫驅(qū)動程序?qū)?chuàng)建一個(gè) Connection 對象并且把它返回中間層服務(wù)器
8、 中間層服務(wù)器將 Connection 對象返回給應(yīng)用程序 Java 應(yīng)用程序,可以認(rèn)為這個(gè) Connection 對象是一個(gè)普通的 JDBC Connection 對象使用它可以和數(shù)據(jù)庫建立。事 實(shí)上的連接與數(shù)據(jù)庫引擎產(chǎn)生交互操作 。
9、 當(dāng)應(yīng)用程序不需要使用 Connection 對象時(shí),可以調(diào)用 Connection 接口的 close() 方 法。請注意這種情況下 close() 方法并沒有關(guān)閉事實(shí)上的數(shù)據(jù)庫連接,僅僅是釋 放了被應(yīng)用程序占用的數(shù)據(jù)庫連接,并將它還給數(shù)據(jù)庫連接緩沖池,數(shù)據(jù)庫連接 緩沖池會自動將這個(gè)數(shù)據(jù)庫連接交給請求隊(duì)列中下一個(gè)的應(yīng)用程序使用。
posted on 2010-02-23 10:36
junly 閱讀(1367)
評論(0) 編輯 收藏 所屬分類:
jdbc/jndi