JNDI在Spring和tomcat下的使用
1. 是什麼
JNDI是 Java 命名與目錄介面(Java Naming and Directory Interface),在J2EE規範中是重要的規範之一。JNDI 在 J2EE 中的角色就是“交換機” —— J2EE 元件在執行時間接地查詢其他元件、資源或服務的通用機制。在多數情況下,提供 JNDI 供應者的容器可以充當有限的資料儲存,這樣管理員就可以設定應用程式的執行屬性,並讓其他應用程式引用這些屬性(Java 管理擴充套件(Java Management Extensions,JMX)也可以用作這個目的)。JNDI 在 J2EE 應用程式中的主要角色就是提供間接層,這樣元件就可以發現所需要的資源,而不用瞭解這些間接性。
2. 為何用
程式設計師可以不用關心“具體的資料庫後臺是什麼?JDBC驅動程式是什麼?訪問資料庫的使用者名稱和口令是什麼?”等等這些問題,而是把這些問題交給J2EE容器來配置和管理,程式設計師只需要對這些配置和管理進行引用即可。
3. 怎麼用
3.1 整體思路
- 在在J2EE容器如Tomcat中配置一個數據源,給這個資料來源設定一個名稱;
- 在專案程式中,通過資料來源名稱引用這個資料來源從而訪問後臺資料庫
3.2 示例
下面在Tomcat6.0+spring+springMVC+mybatis專案中演示用法。
Tomcat
- 方法一:非全域性的Resource,只更改context.xml
在context.xml的根節點Context里加入Resource配置
<Resource name="jdbc/mmcDB" //指定的jndi名稱,會用於spring資料來源bean的配置和ResourceLink的配置
auth="Container"//認證方式,一般預設這個
type="javax.sql.DataSource" //資料來源床型,使用標準的javax.sql.DataSource
driverClassName="com.mysql.jdbc.Driver" //JDBC驅動器
url="jdbc:mysql://localhost:3306/test" //資料庫URL地址
username="test" //資料庫使用者名稱
password="test" //資料庫密碼
maxIdle="40" //最大的空閒連線數
maxWait="4000" //當池的資料庫連線已經被佔用的時候,最大等待時間
maxActive="250" //連線池當中最大的資料庫連線
removeAbandoned="true"
removeAbandonedTimeout="180"
logAbandoned="true" //被丟棄的資料庫連線是否做記錄,以便跟蹤
factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory" />
factory:該Resource 配置使用的是哪個資料來源配置類,這裡使用的是tomcat自帶的標準資料來源Resource配置類,這個類也可以自己寫,實現javax.naming.spi.ObjectFactory 介面即可。
如果使用其他的資料池,如阿里巴巴的druid,要滿足兩個條件:
- 其實現了javax.naming.spi.ObjectFactory,druid的com.alibaba.druid.pool.DruidDataSourceFactory就實現了
- 需把jar及其依賴的jar包 ,都放在tomcat的lib下,光放在工程的WEB-INF/lib下是不夠的。阿里巴巴的druid依賴log4j,所以後者的jar也要複製進去
driverClassName的其他寫法:
oracle:oracle.jdbc.driver.OracleDriver
db2:com.ibm.db2.jcc.DB2Driver
SQLServer:com.microsoft.sqlserver.jdbc.SQLServerDriver
url的其他寫法示例:
oracle:jdbc:oracle:thin:@192.168.1.249:1521:XE
db2:jdbc:db2://18.1.99.7:55555/esdb:currentSchema=EMPSAL
這種配法可寫多個resource給不同的專案使用
方法二:全域性的 Resource,更改server.xml和context.xml
- server.xml:在server.xml的GlobalNamingResources節點裡加入Resource,再在Context節點裡加入ResourceLink的配置。全域性的resource只是為了重用,方便所有該tomcat下的web工程的資料來源管理,但如果你的tomcat不會同時載入多個web工程,也就是說一個tomcat只加載一個web工程時,是沒有必要配置全域性的resource的。
把上面的context.xml的Resource標籤加內容直接拷貝到server.xml的GlobalNamingResources標籤裡就行了
接下來有四種方式引用這個全域性的Resource
方法2沒弄出來,方法1,3,4是可以的,事實上3和4是同一種方法,只要在建專案時在專案的webapps/mmc/META-INF/下寫好context.xml,這兩個方法所要求的context.xml都會在啟動tomcat後自動生成(tomcat7.0沒有自動生成,不過這樣寫過後相當於用來方法4,一樣可以成功啟動)
- 直接在conf/context.xml裡引用
<ResourceLink global="jdbc/mmcDB" name="jdbc/mmcDB" type="javax.sql.DataSource"/>
- 這個方法我用tomcat6.0和7.0都失敗了,報找不到mmcDB,暫時用不到就不深究了,列出了給大家參考吧 ......conf/server.xml裡繼續配置,該方法可以指定把哪些source繫結到哪個web工程下。
<!-- 在host標籤內新增,第一行為載入的工程配置,第二行是該工程需要的ResourceLink配置 --> <context docBase="mmc" path="" reloadable="false"> <ResourceLink global="jdbc/mmcDB" name="jdbc/mmcDB" type="javax.sql.DataSource"/> </context>
- 安裝目錄下的conf/Catalina/localhost/下建立一個xml檔案,檔名是<yourAppName>.xml。比如工程名為mmc,則該xml名為mmc.xml。
<?xml version="1.0" encoding="UTF-8"?> <Context> <ResourceLink global="jdbc/mmcDB" name="jdbc/mmcDB" type="javax.sql.DataSource"/> </context>
- tomcat安裝目錄下的\webapps\test\META-INF\context.xml的Context節點中增加:
<ResourceLink global="jdbc/mmcDB" name="jdbc/mmcDB" type="javax.sql.DataSource"/>
Spring
- 方法一:
<bean id="testDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/mmcDB</value>
</property>
</bean>
或者:
<bean id="testDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/mmcDB</value>
</property>
<property name="resourceRef">
<value>true</value>
</property>
</bean>
- 方式二:
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/mmcDB" />
3.3 細節解釋
Tomcat中在server.xml下配置你必需重啟伺服器才能生效,而context.xml配置儲存後tomcat會自動載入無需重啟
JNDI地址寫法:AB兩種地址的用法可點選參考資料的第一條連結檢視
在描述JNDI,例如獲得資料來源時,JNDI地址 有兩種寫法,例如同是 jdbc/testDS 資料來源:
A: java:comp/env/jdbc/testDS
B: jdbc/testDS
這兩種寫法,配置的方式也不盡相同,用A就行了別糾結,網上查了一堆資料都說的亂七八糟。
java:comp/env 是環境命名上下文(environment naming context(ENC)),是在EJB規範1.1以後引入的,引入這個是為了解決原來JNDI查詢所引起的衝突問題,也是為了提高EJB或者J2EE應用的移植性。
在J2EE中的引用常用的有:
JDBC 資料來源引用在java:comp/env/jdbc 子上下文中宣告
JMS 連線工廠在java:comp/env/jms 子上下文中宣告
JavaMail 連線工廠在java:comp/env/mail 子上下文中宣告
URL 連線工廠在 java:comp/env/url子上下文中宣告
4. 參考資料
- http://stackoverflow.com/questions/4099095/what-does-javacomp-env-do
- http://blog.csdn.net/cyong888/article/details/7361466