鍍金池/ 教程/ Linux/ JNDI 資源
連接器
JSPs
重寫機(jī)制
CGI
Tomcat Manager
Windows 認(rèn)證
代理支持
虛擬主機(jī)
安全性注意事項(xiàng)
如何在 Maven 中使用 Tomcat 庫(kù)
安裝
MBean 描述符
JNDI 資源
類加載機(jī)制
Tomcat Web 應(yīng)用部署
基于 APR 的原生庫(kù)
負(fù)載均衡器
安全管理
附加組件
監(jiān)控與管理
Windows 服務(wù)
集群化與會(huì)話復(fù)制
高級(jí) IO 機(jī)制
SSI(服務(wù)器端嵌入)
WebSocket 支持
JDBC 數(shù)據(jù)源
日志機(jī)制
默認(rèn) Servlet
SSL/TLS 配置
Tomcat 的 JDBC 連接池
第一個(gè)應(yīng)用
簡(jiǎn)介
Realm 配置

JNDI 資源

本章概述

Tomcat 為每個(gè)在其上運(yùn)行的 Web 應(yīng)用都提供了一個(gè) JNDI 的 InitialContext 實(shí)現(xiàn)實(shí)例,它與Java 企業(yè)版應(yīng)用服務(wù)器所提供的對(duì)應(yīng)類完全兼容。Java EE 標(biāo)準(zhǔn)在 /WEB-INF/web.xml 文件中提供了一系列標(biāo)準(zhǔn)元素,用來引用或定義資源。

可通過下列規(guī)范了解如何編寫針對(duì) JNDI 的 API 以及 Java 企業(yè)版(Java EE)服務(wù)器所支持的功能,這也是 Tomcat 針對(duì)其所提供的服務(wù)而仿效的功能。

web.xml 配置

可在 Web 應(yīng)用的部署描述符文件(/WEB-INF/web.xml)中使用下列元素來定義資源:

  • <env-entry> 應(yīng)用的環(huán)境項(xiàng)。一個(gè)可用于配置應(yīng)用運(yùn)行方式的單值參數(shù)。
  • <resource-ref> 資源引用,通常是引用保存某種資源的對(duì)象工廠,比如 JDBC DataSource 或 JavaMail Session 這樣的資源;或者引用配置在 Tomcat 中的自定義對(duì)象工廠中的資源。
  • <resource-env-ref> 資源環(huán)境引用。Servlet 2.4 所添加的一種新 resource-ref,它簡(jiǎn)化了不需要認(rèn)證消息的資源的配置。

有了這些,Tomcat 就能利用適宜的資源工廠來創(chuàng)建資源,再也不需要其他配置信息了。Tomcat 將使用 /WEB-INF/web.xml 中的信息來創(chuàng)建資源。

另外,Tomcat 還提供了一些用于 JNDI 的特殊選項(xiàng),它們沒有指定在 web.xml 中。比如,其中包括的 closeMethod 能在 Web 應(yīng)用停止時(shí),迅速清除 JNDI 資源;singleton 控制是否會(huì)在每次 JNDI 查找時(shí)創(chuàng)建資源的新實(shí)例。要想使用這些配置選項(xiàng),資源必須指定在 Web 應(yīng)用的 <Context> 元素內(nèi),或者位于 $CATALINA_BASE/conf/server.xml<GlobalNamingResources> 元素中。

context.xml 配置

如果 Tomcat 無法確定合適的資源工廠,并且/或者需要額外的配置信息,就必須在 Tomcat 創(chuàng)建資源之前指定好額外的具體配置。Tomcat 特定資源配置應(yīng)位于 <Context> 元素內(nèi),它可以指定在 $CATALINA_BASE/conf/server.xml,或者,最好放在每個(gè) Web 應(yīng)用的上下文 XML 文件中(META-INF/context.xml)。

要想完成 Tomcat 的特定資源配置,需要使用 <Context> 元素中的下列元素:

  • <Environment> 對(duì)將通過 JNDI 的 InitialContext 方法暴露給 Web 應(yīng)用的環(huán)境項(xiàng)的名稱與數(shù)值加以配置(等同于 Web 應(yīng)用部署描述符文件中包含了一個(gè) <env-entry> 元素)。

  • <Resource> 定義應(yīng)用所能用到的資源名稱和數(shù)據(jù)類型(等同于 Web 應(yīng)用部署描述符文件中包含了一個(gè) <resource-ref> 元素)。

  • <ResourceLink> 添加一個(gè)鏈接,使其指向全局 JNDI 上下文中定義的資源。使用資源鏈接可以使 Web 應(yīng)用訪問定義在 <Server> 元素中子元素 <GlobalNamingResources> 中的資源。

  • <Transaction> 添加一個(gè)資源工廠,用于對(duì)從 java:comp/UserTransaction 獲得的 UserTransaction 接口進(jìn)行實(shí)例化。

以上這些元素內(nèi)嵌于 <Context> 元素中,而且是與特定應(yīng)用相關(guān)聯(lián)的。

如果資源已經(jīng)定義在 <Context> 元素中,那就不必再在部署描述符文件中定義它了。但建議在部署描述符文件中保留相關(guān)項(xiàng),以便記錄應(yīng)用資源需求。

加入同樣一個(gè)資源名稱既被定義在 Web 應(yīng)用部署描述符文件的 <env-entry> 元素中,又被定義在 Web 應(yīng)用的 <Context> 元素的 <Environment> 元素內(nèi),那么只有當(dāng)相應(yīng)的 <Environment> 元素允許時(shí)(將其中的 override 屬性設(shè)為 true),部署描述符文件中的值會(huì)優(yōu)先對(duì)待。

全局配置

Tomcat 為整個(gè)服務(wù)器維護(hù)著一個(gè)全局資源的獨(dú)立命名空間。這些全局資源配置在 $CATALINA_BASE/conf/server.xml<GlobalNamingResources> 元素內(nèi)??梢允褂?<ResourceLink>將這些資源暴露給 Web 應(yīng)用,以便在每一應(yīng)用上下文中將其包含進(jìn)來。

如果資源已經(jīng)定義在 <Context> 元素中,那就不必再在部署描述符文件中定義它了。但建議在部署描述符文件中保留相關(guān)項(xiàng),以便記錄應(yīng)用資源需求。

使用資源

當(dāng) Web 應(yīng)用最初部署時(shí),就配置 InitialContext,使其可被 Web 應(yīng)用的各組件所使用(只讀訪問)。JNDI 命名空間的 java:comp/env 部分中包含著所有的配置項(xiàng)與資源,所以訪問資源(在下例中,就是一個(gè) JDBC 數(shù)據(jù)源)應(yīng)按如下形式進(jìn)行:

// 獲取環(huán)境命名上下文
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");

// 查找數(shù)據(jù)源
DataSource ds = (DataSource)
  envCtx.lookup("jdbc/EmployeeDB");

// 分配并使用池中的連接
Connection conn = ds.getConnection();
... use this connection to access the database ...
conn.close();

Tomcat 標(biāo)準(zhǔn)資源工廠

Tomcat 包含一系列資源工廠,能為 Web 應(yīng)用提供各種服務(wù),而且無需修改 Web 應(yīng)用或部署描述符文件即能靈活配置(通過 <Context> 元素)。下面所列出的每一小節(jié)都詳細(xì)介紹了標(biāo)準(zhǔn)資源工廠的配置與用途。

要想了解如何創(chuàng)建、安裝、配置和使用你自己的自定義資源工廠類,請(qǐng)參看添加自定義資源工廠。

注意:在標(biāo)準(zhǔn)資源工廠中,只有“JDBC DataSource”和“User Transaction”工廠可適用于其他平臺(tái),而且這些平臺(tái)必須實(shí)現(xiàn)了 Java EE 規(guī)范。而其他所有標(biāo)準(zhǔn)資源工廠,以及你自己編寫的自定義資源工廠,則都是 Tomcat 所專屬的,不適用于其他容器。

一般 JavaBean 資源

簡(jiǎn)介

該資源工廠能創(chuàng)建出任何符合標(biāo)準(zhǔn) JavaBean 命名規(guī)范1的 Java 類的對(duì)象。如果工廠的 singleton 屬性被設(shè)為 false,那么每當(dāng)對(duì)該項(xiàng)進(jìn)行 lookup 時(shí),資源工廠將會(huì)創(chuàng)建出適合的 bean 類的新實(shí)例。

1. 標(biāo)準(zhǔn)的 JavaBean 命名規(guī)范,比如:構(gòu)造函數(shù)沒有任何參數(shù),屬性設(shè)置器遵守 setFoo() 命名模式,等等。

使用該功能所需的步驟將在下文介紹。

創(chuàng)建 JavaBean 類

創(chuàng)建一個(gè) JavaBean 類,在每次查找資源工廠時(shí),就創(chuàng)建它的實(shí)例。比如,假設(shè)你創(chuàng)建了一個(gè)名叫 com.mycompany.MyBean 的 JavaBean 類,如下所示:

package com.mycompany;

public class MyBean {

  private String foo = "Default Foo";

  public String getFoo() {
    return (this.foo);
  }

  public void setFoo(String foo) {
    this.foo = foo;
  }

  private int bar = 0;

  public int getBar() {
    return (this.bar);
  }

  public void setBar(int bar) {
    this.bar = bar;
  }

}

聲明資源需求

接下來,修改 Web 應(yīng)用部署描述符文件(/WEB-INF/web.xml),聲明 JNDI 名稱,并據(jù)此請(qǐng)求該 Bean 類的新實(shí)例。最簡(jiǎn)單的方法是使用 <resource-env-ref> 元素,如下所示:

<resource-env-ref>
  <description>
    Object factory for MyBean instances.
  </description>
  <resource-env-ref-name>
    bean/MyBeanFactory
  </resource-env-ref-name>
  <resource-env-ref-type>
    com.mycompany.MyBean
  </resource-env-ref-type>
</resource-env-ref>

警告:一定要遵從 Web 應(yīng)用部署描述符文件中 DTD 所需要的元素順序。關(guān)于這點(diǎn),可參看Servlet 規(guī)范中的解釋。

使用資源

資源引用的典型用例如下所示:

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
MyBean bean = (MyBean) envCtx.lookup("bean/MyBeanFactory");

writer.println("foo = " + bean.getFoo() + ", bar = " +
               bean.getBar());

配置 Tomcat 資源工廠

為了配置 Tomcat 資源工廠,為 Web 應(yīng)用的 <Context>元素添加下列元素:

<Context ...>
  ...
  <Resource name="bean/MyBeanFactory" auth="Container"
            type="com.mycompany.MyBean"
            factory="org.apache.naming.factory.BeanFactory"
            bar="23"/>
  ...
</Context>

注意這里的資源名稱,這里 bean/MyBeanFactory 必須跟部署描述符文件中所指定的值完全一樣。這里還初始化了 bar 屬性值,從而當(dāng)返回新的 bean 時(shí),setBar(23) 就會(huì)被調(diào)用。由于我們沒有初始化 foo 屬性(雖然我們完全可以這么做),所以 bean 依然采用構(gòu)造函數(shù)中設(shè)置的默認(rèn)值。

假設(shè)我們的 Bean 如下所示:

package com.mycompany;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class MyBean2 {

  private InetAddress local = null;

  public InetAddress getLocal() {
    return local;
  }

  public void setLocal(InetAddress ip) {
    local = ip;
  }

  public void setLocal(String localHost) {
    try {
      local = InetAddress.getByName(localHost);
    } catch (UnknownHostException ex) {
    }
  }

  private InetAddress remote = null;

  public InetAddress getRemote() {
    return remote;
  }

  public void setRemote(InetAddress ip) {
    remote = ip;
  }

  public void host(String remoteHost) {
    try {
      remote = InetAddress.getByName(remoteHost);
    } catch (UnknownHostException ex) {
    }
  }

}

該 Bean 有兩個(gè) InetAddress 類型的屬性。第一個(gè)屬性 local 還有第二種 setter 方法,傳入的是一個(gè)字符串參數(shù)。默認(rèn) Tomcat BeanFactory 會(huì)使用自動(dòng)偵測(cè)到的 setter 方法,并將其參數(shù)類型作為屬性類型,然后拋出一個(gè) NamingException(命名異常),因?yàn)樗€沒有準(zhǔn)備好將給定字符串值轉(zhuǎn)化為 InetAddress。我們可以讓 Tomcat BeanFactory 使用其他的 setter 方法,如下所示:

<Context ...>
  ...
  <Resource name="bean/MyBeanFactory" auth="Container"
            type="com.mycompany.MyBean2"
            factory="org.apache.naming.factory.BeanFactory"
            forceString="local"
            local="localhost"/>
  ...
</Context>

bean 屬性 remote 也可以從字符串中設(shè)置,但必須使用非標(biāo)準(zhǔn)方法 host。如下設(shè)置 localremote

<Context ...>
  ...
  <Resource name="bean/MyBeanFactory" auth="Container"
            type="com.mycompany.MyBean2"
            factory="org.apache.naming.factory.BeanFactory"
            forceString="local,remote=host"
            local="localhost"
            remote="tomcat.apache.org"/>
  ...
</Context>

如上所示,可以利用逗號(hào)作分隔符,將多個(gè)屬性描述串聯(lián)在一起放在 forceString 中。每一屬性描述要么只包含屬性名,要么由 name = method 的結(jié)構(gòu)所組成。對(duì)于前者的情況,BeanFactory 會(huì)直接調(diào)用屬性名的 setter 方法;而對(duì)于后者,則通過調(diào)用方法 method 來設(shè)置屬性名 name。對(duì)于 String 或基本類型,或者相應(yīng)的基本包裝器類的屬性,不必使用 forceString。會(huì)自動(dòng)偵測(cè)正確的 setter 并實(shí)施參數(shù)類型轉(zhuǎn)換。

UserDatabase 資源

簡(jiǎn)介

UserDatabase 資源通常被配置成通過 UserDataBase Realm 所使用的全局資源。Tomcat 包含一個(gè) UserDatabaseFactoory,能夠創(chuàng)建基于 XML 文件(通常是 tomcat-users.xml)的 UserDatabase 資源。

建立全局的 UserDataBase 資源的步驟如下。

創(chuàng)建/編輯 XML 文件

XML 文件通常位于 $CATALINA_BASE/conf/tomcat-users.xml,但也可以放在文件系統(tǒng)中的任何位置。我們建議把該文件放在 $CATALINA_BASE/conf。典型的 XML 應(yīng)如下所示:

<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
  <role rolename="tomcat"/>
  <role rolename="role1"/>
  <user username="tomcat" password="tomcat" roles="tomcat"/>
  <user username="both" password="tomcat" roles="tomcat,role1"/>
  <user username="role1" password="tomcat" roles="role1"/>
</tomcat-users>

聲明資源

接下來,修改 $CATALINA_BASE/conf/server.xml 來創(chuàng)建基于此文件的 UserDataBase 資源。如下所示:

<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"
          readonly="false" />

屬性 pathname 可以采用絕對(duì)路徑或相對(duì)路徑。相對(duì)路徑意味著是相對(duì)于 $CATALINA_BASE。

readonly 屬性是可選屬性,如果不采用,則默認(rèn)為 true。如果該 XML 文件可寫,那么當(dāng) Tomcat 開啟時(shí),就會(huì)被修改。警告:當(dāng)該文件被修改后,它會(huì)繼承 Tomcat 目前運(yùn)行用戶的默認(rèn)文件權(quán)限。所以要確保這樣做是否能保持應(yīng)用的安全性。

配置 Realm

配置 UserDatabase Realm 以便使用該資源,詳情可參看 Realm 配置文檔

JavaMail 會(huì)話

簡(jiǎn)介

很多 Web 應(yīng)用都會(huì)把發(fā)送電子郵件作為系統(tǒng)的必備功能。JavaMail API 可以讓這一過程變得相對(duì)簡(jiǎn)單些,但需要很多的配置細(xì)節(jié),客戶端應(yīng)用必須知道的(包括用于發(fā)送消息的 SMTP 主機(jī)的名稱)。

Tomcat 所包含的標(biāo)準(zhǔn)資源工廠可以為你創(chuàng)建 javax.mail.Session 會(huì)話實(shí)例,并且已經(jīng)配置好連接到 SMTP 服務(wù)器上,從而使應(yīng)用完全與電子郵件配置環(huán)境相隔離,不受后者變更的影響,無論何時(shí),只需請(qǐng)求并接受預(yù)配置的會(huì)話即可。

所需步驟如下所示。

聲明資源需求

首先應(yīng)該做的是修改 Web 應(yīng)用的部署描述符文件(/WEB-INF/web.xml),聲明 JNDI 名稱以便借此查找預(yù)配置會(huì)話。按照慣例,所有這樣的名字都應(yīng)該解析到 mail 子上下文(相對(duì)于標(biāo)準(zhǔn)的 java:comp/env 命名上下文而言的,這個(gè)命名上下文是所有資源工廠的基準(zhǔn)。)典型的 web.xml 項(xiàng)應(yīng)該如下所示:

<resource-ref>
  <description>
    Resource reference to a factory for javax.mail.Session
    instances that may be used for sending electronic mail
    messages, preconfigured to connect to the appropriate
    SMTP server.
  </description>
  <res-ref-name>
    mail/Session
  </res-ref-name>
  <res-type>
    javax.mail.Session
  </res-type>
  <res-auth>
    Container
  </res-auth>
</resource-ref>

警告:一定要遵從 Web 應(yīng)用部署描述符文件中 DTD 所需要的元素順序。關(guān)于這點(diǎn),可參看Servlet 規(guī)范中的解釋。

使用資源

資源引用的典型用例如下所示:

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
Session session = (Session) envCtx.lookup("mail/Session");

Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(request.getParameter("from")));
InternetAddress to[] = new InternetAddress[1];
to[0] = new InternetAddress(request.getParameter("to"));
message.setRecipients(Message.RecipientType.TO, to);
message.setSubject(request.getParameter("subject"));
message.setContent(request.getParameter("content"), "text/plain");
Transport.send(message);

注意,該應(yīng)用所用的資源引用名與 Web 應(yīng)用部署符中聲明的完全相同。這是與下文會(huì)講到的 <Context> 元素里所配置的資源工廠相匹配的。

配置 Tomcat 資源工廠

為了配置 Tomcat 的資源工廠,在 <Context> 元素中添加以下元素:

<Context ...>
  ...
  <Resource name="mail/Session" auth="Container"
            type="javax.mail.Session"
            mail.smtp.host="localhost"/>
  ...
</Context>

注意,資源名(在這里,是 mail/Session)必須與 Web 應(yīng)用部署描述符文件中所指定的值相匹配。對(duì)于 mail.smtp.host 參數(shù)值,可以用為你的網(wǎng)絡(luò)提供 SMTP 服務(wù)的服務(wù)器來自定義。

額外的資源屬性與值將轉(zhuǎn)換成相關(guān)的屬性及值,并被傳入 javax.mail.Session.getInstance(java.util.Properties),作為參數(shù)集 java.util.Properties 中的一部分。除了 JavaMail 規(guī)范附件A中所定義的屬性之外,個(gè)別的提供者可能還支持額外的屬性。

如果資源配置中包含 password 屬性,以及 mail.smtp.usermail.user 屬性,那么 Tomcat 資源工廠將配置并添加 javax.mail.Authenticator 到郵件會(huì)話中。

安裝 JavaMail 庫(kù)

下載 JavaMail API

解壓縮文件分發(fā)包,將 mail.jar 放到 $CATALINA_HOME/lib 中,從而使 Tomcat 能在郵件會(huì)話資源初始化期間能夠使用它。注意:不能將這一文件同時(shí)放在 $CATALINA_HOME/lib 和 Web 應(yīng)用的 /lib 文件夾中,否則就會(huì)出錯(cuò),只能將其放在 $CATALINA_HOME/lib 中。

重啟 Tomcat

為了能讓 Tomcat 使用這個(gè)額外的 jar 文件,必須重啟 Tomcat 實(shí)例。

范例應(yīng)用

Tomcat 中的 /examples 應(yīng)用中帶有一個(gè)使用該資源工廠的范例??梢酝ㄟ^“JSP 范例”的鏈接來訪問它。實(shí)際發(fā)送郵件的 servlet 的源代碼則位于 /WEB-INF/classes/SendMailServlet.java 中。

警告:默認(rèn)配置在 localhost 的 端口 25 上的 SMTP 服務(wù)器。如果實(shí)際情況不符,則需要編輯該 Web 應(yīng)用的 <Context> 元素,將 mail.smtp.host 參數(shù)的值修改為你的網(wǎng)絡(luò)上的 SMTP 服務(wù)器的主機(jī)名。

JDBC 數(shù)據(jù)源

簡(jiǎn)介

許多 Web 應(yīng)用都需要 JDBC 驅(qū)動(dòng)來訪問數(shù)據(jù)庫(kù),以便能夠支持該應(yīng)用所需要的功能。Java EE 平臺(tái)規(guī)范要求 Java EE 應(yīng)用服務(wù)器針對(duì)該需求提供一個(gè) DataSource 實(shí)現(xiàn)(也就是說,用于 JDBC 連接的連接池)。Tomcat 就能提供同樣的支持,因此在 Tomcat 上,由于使用了這種服務(wù),基于數(shù)據(jù)庫(kù)的應(yīng)用可以不用修改就能移植到任何 Java EE 服務(wù)器上運(yùn)行。

要想詳細(xì)了解 JDBC,可以參考以下網(wǎng)站或信息來源:

注意:Tomcat 默認(rèn)所支持的數(shù)據(jù)源是基于 Commons 項(xiàng)目DBCP 連接池。但也可以通過編寫自定義的資源工廠,使用其他實(shí)現(xiàn)了 javax.sql.DataSource 的連接池,詳見下文。

安裝 JDBC 驅(qū)動(dòng)

使用 JDBC 數(shù)據(jù)源的 JNDI 資源工廠需要一個(gè)適合的 JDBC 驅(qū)動(dòng),要求它既能被 Tomcat 內(nèi)部類所使用,也能被你的 Web 應(yīng)用所使用。這很容易實(shí)現(xiàn),只需將驅(qū)動(dòng)的 JAR 文件(或多個(gè)文件)安裝到 $CATALINA_HOME/lib 目錄中即可,這樣資源工廠和應(yīng)用就都能使用了這一驅(qū)動(dòng)了。

聲明資源需求

下一步,修改 Web 應(yīng)用的部署描述符文件(/WEB-INF/web.xml),聲明 JNDI 名稱以便借此查找預(yù)配置的數(shù)據(jù)源。按照慣例,所有這樣的名稱都應(yīng)該在jdbc 子上下文中聲明(這個(gè)“子”是相對(duì)于標(biāo)準(zhǔn)的 java:comp/env 環(huán)境命名上下文而言的。java:comp/env 環(huán)境命名上下文是所有資源工廠的根引用)。典型的 web.xml 文件應(yīng)如下所示:

<resource-ref>
  <description>
    Resource reference to a factory for java.sql.Connection
    instances that may be used for talking to a particular
    database that is configured in the <Context>
    configurartion for the web application.
  </description>
  <res-ref-name>
    jdbc/EmployeeDB
  </res-ref-name>
  <res-type>
    javax.sql.DataSource
  </res-type>
  <res-auth>
    Container
  </res-auth>
</resource-ref>

警告:一定要遵從 Web 應(yīng)用部署描述符文件中 DTD 所需要的元素順序。關(guān)于這點(diǎn),可參看Servlet 規(guī)范中的解釋。

使用資源

資源引用的典型用例如下所示:

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource ds = (DataSource)
  envCtx.lookup("jdbc/EmployeeDB");

Connection conn = ds.getConnection();
... use this connection to access the database ...
conn.close();

注意,該應(yīng)用所用的資源引用名與 Web 應(yīng)用部署符中聲明的完全相同。這是與下文會(huì)講到的 <Context> 元素里所配置的資源工廠相匹配的。

配置 Tomcat 資源工廠

為了配置 Tomcat 的資源工廠,在 <Context> 元素中添加以下元素:

<Context ...>
  ...
  <Resource name="jdbc/EmployeeDB"
            auth="Container"
            type="javax.sql.DataSource"
            username="dbusername"
            password="dbpassword"
            driverClassName="org.hsql.jdbcDriver"
            url="jdbc:HypersonicSQL:database"
            maxTotal="8"
            maxIdle="4"/>
  ...
</Context>

注意上述代碼中的資源名(這里是 jdbc/EmployeeDB)必須跟 Web 應(yīng)用部署描述符文件中指定的值相同。

該例假定使用的是 HypersonicSQL 數(shù)據(jù)庫(kù) JDBC 驅(qū)動(dòng)??勺远x driverClassNamedriverName 參數(shù),使其匹配實(shí)際數(shù)據(jù)庫(kù)的 JDBC 驅(qū)動(dòng)與連接 URL。

Tomcat 標(biāo)準(zhǔn)數(shù)據(jù)源資源工廠(org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory)的配置屬性如下:

  • driverClassName 所用的 JDBC 驅(qū)動(dòng)的完全合格的類名。
  • username JDBC 驅(qū)動(dòng)所要接受的數(shù)據(jù)庫(kù)用戶名。
  • password JDBC 驅(qū)動(dòng)所要接受的數(shù)據(jù)庫(kù)密碼。
  • url 傳入 JDBC 驅(qū)動(dòng)的連接 URL(為了向后兼容性考慮,也同樣認(rèn)可 driverName 屬性,即與之等同)。
  • initialSize 連接池初始化過程中所創(chuàng)建的初始連接的數(shù)目。默認(rèn)為 0。
  • maxTotal 連接池同時(shí)所能分配的最大連接數(shù)。默認(rèn)為 8。
  • minIdle 連接池中同時(shí)空閑的最少連接數(shù)。默認(rèn)為 0。
  • maxIdle 連接池中同時(shí)空閑的最多連接數(shù)。默認(rèn)為 8。
  • maxWaitMillis 在拋出異常前,連接池等待(沒有可用的連接)連接返回的最長(zhǎng)等待毫秒數(shù)。默認(rèn)為 -1(無限長(zhǎng)時(shí)間)。

還有一些額外的用來驗(yàn)證連接的屬性,如下所示:

  • validationQuery 在連接返回應(yīng)用之前,連接池用于驗(yàn)證連接的 SQL 查詢。如果指定了該屬性值,查詢必須是一個(gè)至少能返回一行的 SQL SELECT 語句。
  • validationQueryTimeout 驗(yàn)證查詢返回的超時(shí)時(shí)間。默認(rèn)為 -1(無限長(zhǎng)時(shí)間)。
  • testOnBorrow 布爾值,true 或 false,針對(duì)每次從連接池中借出的連接,判斷是否應(yīng)用驗(yàn)證查詢對(duì)其驗(yàn)證。默認(rèn):true。
  • testOnReturn 布爾值,true 或 false,針對(duì)每次歸還給連接池的連接,判斷是否應(yīng)用驗(yàn)證查詢對(duì)其驗(yàn)證。默認(rèn):false。

可選的 evictor thread 會(huì)清除空閑較長(zhǎng)時(shí)間的連接,從而縮小連接池。evictor thread 不受 minIdle 屬性值的空閑。注意,如果你只想通過配置的 minIdle 屬性來縮小連接池,那么不需要使用 evictor thread。

默認(rèn) evictor 是禁用的,另外,可以使用下列屬性來配置它:

  • timeBetweenEvictionRunsMillis evictor 線程連續(xù)運(yùn)行之間的毫秒數(shù)。默認(rèn)為 -1(禁止)
  • numTestsPerEvictionRun evictor 每次運(yùn)行中,evictor 實(shí)施的用來檢測(cè)空閑與否的連接數(shù)目。默認(rèn)為 3。
  • minEvictableIdleTimeMillis evictor 從連接池中清除某連接后的空閑時(shí)間,以毫秒計(jì),默認(rèn)為 30 * 60 * 1000(30分鐘)。
  • testWhileIdle 布爾值,true 或 false。對(duì)于在連接池中處于空閑狀態(tài)的連接,是否應(yīng)被 evictor 線程通過驗(yàn)證查詢來驗(yàn)證。默認(rèn)為false。

另一個(gè)可選特性是對(duì)廢棄連接的移除。如果應(yīng)用很久都不把某個(gè)連接返回給連接池,那么該連接就被稱為廢棄連接。連接池就會(huì)自動(dòng)關(guān)閉這樣的連接,并將其從池中移除。這么做是為了防止應(yīng)用泄露連接。

默認(rèn)是禁止廢棄連接的,可以通過下列屬性來配置:

  • removeAbandoned 布爾值,true 或 false。確定是否去除連接池中的廢棄連接。默認(rèn)為 false。
  • removeAbandonedTimeout 經(jīng)過多少秒后,借用的連接可以認(rèn)為被廢棄。默認(rèn)為 300。
  • logAbandoned 布爾值,true 或 false。確定是否需要針對(duì)廢棄了語句或連接的應(yīng)用代碼來記錄堆棧跟蹤。如果記錄的話,將會(huì)帶來很大的開銷。默認(rèn)為 false。

最后再介紹一些可以對(duì)連接池行為進(jìn)行進(jìn)一步微調(diào)的屬性:

  • defaultAutoCommit 布爾值,truefalse。由連接池所創(chuàng)建的連接的默認(rèn)自動(dòng)提交狀態(tài)。默認(rèn)為 true。
  • defaultReadOnly 布爾值,truefalse。由連接池所創(chuàng)建的連接的默認(rèn)只讀狀態(tài)。默認(rèn)為 false。
  • defaultTransactionIsolation 設(shè)定默認(rèn)的事務(wù)隔離級(jí)別??扇≈禐椋?code>NONE、READ_COMMITTED、READ_UNCOMMITTEDREPEATABLE_READSERIALIZABLE。沒有默認(rèn)設(shè)置。
  • poolPreparedStatements 布爾值,true 或 false。 是否池化 PreparedStatements 和 CallableStatements。默認(rèn)為 false
  • maxOpenPreparedStatements 同時(shí)能被語句池分配的開放語句的最大數(shù)目。默認(rèn)為 -1(無限)
  • defaultCatalog catalog 默認(rèn)值。默認(rèn)值:未設(shè)定。
  • connectionInitSqls 連接建立后運(yùn)行的一系列 SQL 語句。各個(gè)語句間用分號(hào)(;)進(jìn)行分隔。默認(rèn)為:沒有語句。
  • connectionInitSqls 傳入驅(qū)動(dòng)用于創(chuàng)建連接的驅(qū)動(dòng)特定屬性。每一屬性都以 name = value 的形式給出,多個(gè)屬性用分號(hào)(;)進(jìn)行分隔。默認(rèn):沒有屬性。
  • accessToUnderlyingConnectionAllowed 布爾值,truefalse。 是否可訪問底層連接。默認(rèn)為 false。

要想更詳細(xì)地了解這些屬性,請(qǐng)參閱 commons-dbcp 文檔。

添加自定義資源工廠

如果標(biāo)準(zhǔn)資源工廠無法滿足你的需求,你還可以自己編寫資源工廠,然后將其集成到 Tomcat 中,在 Web 應(yīng)用的 <Context> 元素中配置該工廠的使用方式。在下面的范例中,我們將創(chuàng)建一個(gè)資源工廠,只懂得如何 com.mycompany.MyBean bean

編寫資源工廠類

你必須編寫一個(gè)類來實(shí)現(xiàn) JNDI 服務(wù)提供者 javax.naming.spi.ObjectFactory 接口。每次 Web 應(yīng)用在綁定到該工廠(假設(shè)該工廠配置中,singleton = "false")的上下文項(xiàng)上調(diào)用 lookup() 時(shí),就會(huì)調(diào)用 getObjectInstance() 方法,該方法有如下這些參數(shù):

  • Object obj

創(chuàng)建一個(gè)能夠生成 MyBean 實(shí)例的資源工廠,需要像下面這樣來創(chuàng)建類:

package com.mycompany;

import java.util.Enumeration;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;

public class MyBeanFactory implements ObjectFactory {

  public Object getObjectInstance(Object obj,
      Name name, Context nameCtx, Hashtable environment)
      throws NamingException {

      // Acquire an instance of our specified bean class
      MyBean bean = new MyBean();

      // Customize the bean properties from our attributes
      Reference ref = (Reference) obj;
      Enumeration addrs = ref.getAll();
      while (addrs.hasMoreElements()) {
          RefAddr addr = (RefAddr) addrs.nextElement();
          String name = addr.getType();
          String value = (String) addr.getContent();
          if (name.equals("foo")) {
              bean.setFoo(value);
          } else if (name.equals("bar")) {
              try {
                  bean.setBar(Integer.parseInt(value));
              } catch (NumberFormatException e) {
                  throw new NamingException("Invalid 'bar' value " + value);
              }
          }
      }

      // Return the customized instance
      return (bean);

  }

}

// Acquire an instance of our specified bean class 需要我們所指定的bean 類的一個(gè)實(shí)例

// Customize the bean properties from our attributes 從屬性中自定義 bean 屬性。

// Return the customized instance 返回自定義實(shí)例

在上例中,無條件地創(chuàng)建了 com.mycompany.MyBean 類的一個(gè)新實(shí)例, 并根據(jù)工廠配置中的 <ResourceParams> 元素(下文詳述)包括的參數(shù)來填充這一實(shí)例。你應(yīng)該記住,必須忽略任何名為 factory 的參數(shù)——參數(shù)應(yīng)該用來指定工廠類自身的名字(com.mycompany.MyBeanFactory),而不是配置的 bean 屬性。

關(guān)于 ObjectFactory 的更多信息,可參見 JNDI 服務(wù)提供者接口(SPI)規(guī)范。

首先參照一個(gè) $CATALINA_HOME/lib 目錄中包含所有 JAR 文件的類路徑來編譯該類。完成之后,將這個(gè)工廠類以及相應(yīng)的 Bean 類解壓縮到 $CATALINA_HOME/lib,或者 $CATALINA_HOME/lib 內(nèi)的一個(gè) JAR 文件中。這樣,所需的類文件就能被 Catalina 內(nèi)部資源與 Web 應(yīng)用看到了。

聲明資源需求

下一步,修改 Web 應(yīng)用的部署描述符文件(/WEB-INF/web.xml),聲明 JNDI 名稱以便借此請(qǐng)求該 bean 的新實(shí)例。最簡(jiǎn)單的方法是使用 <resource-env-ref> 元素,如下所示:

<resource-env-ref>
  <description>
    Object factory for MyBean instances.
  </description>
  <resource-env-ref-name>
    bean/MyBeanFactory
  </resource-env-ref-name>
  <resource-env-ref-type>
    com.mycompany.MyBean
  </resource-env-ref-type>
<resource-env-ref>

警告:一定要遵從 Web 應(yīng)用部署描述符文件中 DTD 所需要的元素順序。關(guān)于這點(diǎn),可參看Servlet 規(guī)范中的解釋。

使用資源

資源引用的典型用例如下所示:

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
MyBean bean = (MyBean) envCtx.lookup("bean/MyBeanFactory");

writer.println("foo = " + bean.getFoo() + ", bar = " +
               bean.getBar());

配置 Tomcat 資源工廠

為了配置 Tomcat 的資源工廠,在 <Context> 元素中添加以下元素:

<Context ...>
  ...
  <Resource name="bean/MyBeanFactory" auth="Container"
            type="com.mycompany.MyBean"
            factory="com.mycompany.MyBeanFactory"
            singleton="false"
            bar="23"/>
  ...
</Context>

注意上述代碼中的資源名(這里是 bean/MyBeanFactory)必須跟 Web 應(yīng)用部署描述符文件中指定的值相同。另外,我們還初始化了 bar 屬性值,從而在返回新 bean 時(shí),導(dǎo)致 setBar(23) 被調(diào)用。由于我們沒有初始化 foo 屬性(雖然完全可以這樣做),所以 bean 將含有構(gòu)造函數(shù)所定義的各種默認(rèn)值。

另外,你肯定能注意到,從應(yīng)用開發(fā)者的角度來看,資源環(huán)境引用的聲明,以及請(qǐng)求新實(shí)例的編程方式,都跟通用 JavaBean 資源(Generic JavaBean Resources)范例所用方式如出一轍。這揭示了使用 JNDI 資源封裝功能的一個(gè)優(yōu)點(diǎn):只要維持兼容的 API,無需修改使用資源的應(yīng)用,只需改變底層實(shí)現(xiàn)。

上一篇:WebSocket 支持