JNDI 資源操作指南
目錄
簡介
Tomcat 為在它底下執行的每個 Web 應用程式提供一個 JNDI InitialContext 實作執行個體,其方式與 Jakarta EE 應用程式伺服器所提供的相容。Jakarta EE 標準在 /WEB-INF/web.xml
檔案中提供一組標準元素,用於參照/定義資源。
請參閱下列規格,以取得有關 JNDI 程式設計 API 的更多資訊,以及 Jakarta EE 伺服器支援的功能,Tomcat 模擬這些功能以提供其服務
- Java 命名和目錄介面 (包含在 JDK 1.4 及後續版本中)
- Jakarta EE 平台規格 (特別是,請參閱第 5 章「命名」)
web.xml 組態
下列元素可用於 Web 應用程式的 Web 應用程式部署描述符 (/WEB-INF/web.xml
) 中,以定義資源
<env-entry>
- 環境條目,一個單值參數,可用於設定應用程式運作的方式。<resource-ref>
- 資源參照,通常是 JDBCDataSource
、Jakarta MailSession
或設定到 Tomcat 中的客製化物件工廠等資源的物件工廠。<resource-env-ref>
- 資源環境參照,resource-ref
在 Servlet 2.4 中新增的變異,對於不需要驗證資訊的資源,設定較為簡單。
假設 Tomcat 能夠辨識適當的資源工廠用於建立資源,且不需要進一步的設定資訊,Tomcat 會使用 /WEB-INF/web.xml
中的資訊來建立資源。
Tomcat 為 JNDI 資源提供多個 Tomcat 特定的選項,這些選項無法在 web.xml 中指定。這些選項包括 closeMethod
,它可以在 Web 應用程式停止時加快 JNDI 資源的清除,以及 singleton
,它控制是否為每個 JNDI 查詢建立資源的新執行個體。若要使用這些設定選項,資源必須在 Web 應用程式的 <Context>
元素中或 $CATALINA_BASE/conf/server.xml
的 <GlobalNamingResources>
元素中指定。
context.xml 組態
如果 Tomcat 無法識別適當的資源工廠和/或需要額外的組態資訊,則必須在 Tomcat 建立資源之前指定額外的 Tomcat 特定組態。Tomcat 特定資源組態輸入在 <Context>
元素中,可以指定在 $CATALINA_BASE/conf/server.xml
或(較佳)每個 Web 應用程式內容 XML 檔案 (META-INF/context.xml
) 中。
Tomcat 特定資源組態使用 <Context>
元素中的下列元素執行
- <Environment> - 為會透過 JNDI
InitialContext
公開給 Web 應用程式的標量環境項目組態名稱和值(等於在 Web 應用程式部署描述子中包含<env-entry>
元素)。 - <Resource> - 組態提供給應用程式的資源名稱和資料類型(等於在 Web 應用程式部署描述子中包含
<resource-ref>
元素)。 - <ResourceLink> - 新增連結到在全域 JNDI 內容中定義的資源。使用資源連結讓 Web 應用程式存取在 <GlobalNamingResources>(<Server> 元素的子元素)中定義的資源。
- <Transaction> - 新增資源工廠,用於實例化可在
java:comp/UserTransaction
取得的 UserTransaction 物件實例。
這些元素的任何數量都可以巢狀於 <Context>
元素內,而且只會與該特定 Web 應用程式關聯。
如果資源已在 <Context>
元素中定義,則不必在 /WEB-INF/web.xml
中定義該資源。不過,建議在 /WEB-INF/web.xml
中保留項目,以記錄 Web 應用程式的資源需求。
如果已為包含在 Web 應用程式部署描述子 (/WEB-INF/web.xml
) 中的 <env-entry>
元素和在 <Context>
元素(作為 Web 應用程式的部分)中作為 <Environment>
元素的一部分定義了相同的資源名稱,則只有在對應的 <Environment>
元素允許(透過將 override
屬性設定為「true」)的情況下,部署描述子中的值才會優先。
全域組態
Tomcat 為整個伺服器維護一個獨立的全球資源命名空間。這些資源在 $CATALINA_BASE/conf/server.xml
的 <GlobalNamingResources>
元素中設定。您可以使用 <ResourceLink>
將這些資源包含在每個 Web 應用程式內容中,以將這些資源公開給 Web 應用程式。
如果已使用 <ResourceLink>
定義資源,則不需要在 /WEB-INF/web.xml
中定義該資源。但是,建議保留 /WEB-INF/web.xml
中的項目,以記錄 Web 應用程式的資源需求。
使用資源
InitialContext
會在最初部署 Web 應用程式時設定,並提供給 Web 應用程式元件(用於唯讀存取)。所有設定的項目和資源都會放置在 JNDI 命名空間的 java:comp/env
部分,因此,對資源的典型存取(在本例中,對 JDBC DataSource
的存取)會類似下列範例
// Obtain our environment naming context
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
// Look up our data source
DataSource ds = (DataSource)
envCtx.lookup("jdbc/EmployeeDB");
// Allocate and use a connection from the pool
Connection conn = ds.getConnection();
... use this connection to access the database ...
conn.close();
Tomcat 標準資源工廠
Tomcat 包含一系列標準資源工廠,這些工廠可以為您的 Web 應用程式提供服務,但讓您透過 <Context>
元素(而非修改 Web 應用程式或部署描述符)彈性設定。下列每個小節都會詳細說明標準資源工廠的設定和用法。
請參閱 新增自訂資源工廠,以取得有關如何建立、安裝、設定和使用您自己的自訂資源工廠類別與 Tomcat 的資訊。
注意 - 在標準資源工廠中,只有「JDBC 資料來源」和「使用者交易」工廠強制要求在其他平台上可用,而且只有在平台實作 Jakarta EE 規格時才需要這些工廠。所有其他標準資源工廠,以及您自己撰寫的自訂資源工廠,都是專屬於 Tomcat,而且無法假設在其他容器中可用。
一般 JavaBean 資源
0. 簡介
此資源工廠可用於建立符合標準 JavaBeans 命名慣例的任何 Java 類別物件(亦即,它有一個零引數建構函式,而且有符合 setFoo() 命名模式的屬性設定器。如果工廠的 singleton
屬性設定為 false
,則資源工廠只會在每次對此項目進行 lookup()
時建立適當 bean 類別的新執行個體。
使用此功能所需的步驟如下所述。
1. 建立 JavaBean 類別
建立 JavaBean 類別,每次查詢資源工廠時都會實例化該類別。在此範例中,假設您建立一個類別 com.mycompany.MyBean
,如下所示
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;
}
}
2. 宣告您的資源需求
接著,修改您的 Web 應用程式部署描述符 (/WEB-INF/web.xml
) 以宣告您將在該宣告中要求此 Bean 的新實例的 JNDI 名稱。最簡單的方法是使用 <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 應用程式部署描述符的 DTD 所要求的元素順序!請參閱 Servlet 規格 以取得詳細資訊。
3. 編寫您的應用程式使用此資源的程式碼
此資源環境參考的典型用法可能如下所示
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());
4. 設定 Tomcat 的資源工廠
若要設定 Tomcat 的資源工廠,請將類似這樣的元素新增到此 Web 應用程式的 <Context>
元素。
<Context ...>
...
<Resource name="bean/MyBeanFactory" auth="Container"
type="com.mycompany.MyBean"
factory="org.apache.naming.factory.BeanFactory"
bar="23"/>
...
</Context>
請注意資源名稱 (在此為 bean/MyBeanFactory
) 必須與 Web 應用程式部署描述符中指定的數值相符。我們也正在初始化 bar
屬性的值,這將導致在傳回新的 Bean 之前呼叫 setBar(23)
。由於我們沒有初始化 foo
屬性 (儘管我們可以初始化),因此 Bean 將包含由其建構函式設定的任何預設值。
如果 Bean 屬性的類型為 String
,BeanFactory 將使用提供的屬性值呼叫屬性設定器。如果 Bean 屬性類型是基本型別或基本型別包裝器,BeanFactory 將會將值轉換為適當的基本型別或基本型別包裝器,然後在呼叫設定器時使用該值。有些 Bean 具有無法自動從 String
轉換的類型屬性。如果 Bean 提供具有相同名稱且採用 String
的替代設定器,BeanFactory 將嘗試使用該設定器。如果 BeanFactory 無法使用該值或執行適當的轉換,設定屬性將會失敗並產生 NamingException。
forceString
屬性在較早的 Tomcat 版本中可用,但已移除作為安全性強化措施。
記憶體 UserDatabase 資源
0. 簡介
UserDatabase 資源通常設定為 UserDatabase 領域使用的全域資源。Tomcat 包含一個 UserDatabaseFactory,它會建立由 XML 檔 (通常為 tomcat-users.xml
) 支援的 UserDatabase 資源。
設定全域 UserDatabase 資源所需的步驟如下所述。
1. 建立/編輯 XML 檔案
XML 檔案通常位於 $CATALINA_BASE/conf/tomcat-users.xml
,不過你可以將檔案放在檔案系統中的任何位置。建議將 XML 檔案放在 $CATALINA_BASE/conf
。典型的 XML 如下所示
<?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>
2. 宣告你的資源
接著,修改 $CATALINA_BASE/conf/server.xml
以根據你的 XML 檔案建立 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
屬性可以是 URL、絕對路徑或相對路徑。如果是相對路徑,則相對於 $CATALINA_BASE
。
readonly
屬性是選用的,如果未提供,則預設為 true
。如果 XML 可寫入,則在 Tomcat 啟動時會寫入。警告:當檔案寫入時,它會繼承 Tomcat 使用者執行的預設檔案權限。確保這些權限適合於維護安裝的安全性。
如果在 Realm 中參照,UserDatabase 預設會監控 pathname
的變更,並在觀察到上次修改時間變更時重新載入檔案。這可以透過將 watchSource
屬性設定為 false
來停用。
3. 設定 Realm
設定 UserDatabase Realm 以使用此資源,如 Realm 設定文件 中所述。
DataSource UserDatabase 資源
0. 簡介
Tomcat 還包含一個使用 DataSource
資源作為後端的 UserDatabase
。後端資源必須在與將使用它的使用者資料庫相同的 JNDI 環境中宣告。
設定全域 UserDatabase 資源所需的步驟如下所述。
1. 資料庫架構
使用者資料庫的資料庫架構很靈活。它可以與 DataSourceRealm
使用的架構相同,只有一個使用者資料表(使用者名稱、密碼),以及另一個列出與每個使用者相關聯的角色。若要支援完整的 UserDatabase
功能,它必須包含群組的其他資料表,並與使用者、群組和角色之間的參考完整性相容。
具有群組和參考完整性的完整功能架構可以是
create table users (
user_name varchar(32) not null primary key,
user_pass varchar(64) not null,
user_fullname varchar(128)
-- Add more attributes as needed
);
create table roles (
role_name varchar(32) not null primary key,
role_description varchar(128)
);
create table groups (
group_name varchar(32) not null primary key,
group_description varchar(128)
);
create table user_roles (
user_name varchar(32) references users(user_name),
role_name varchar(32) references roles(role_name),
primary key (user_name, role_name)
);
create table user_groups (
user_name varchar(32) references users(user_name),
group_name varchar(32) references groups(group_name),
primary key (user_name, group_name)
);
create table group_roles (
group_name varchar(32) references groups(group_name),
role_name varchar(32) references roles(role_name),
primary key (group_name, role_name)
);
沒有使用群組功能的最小架構將是(與 DataSourceRealm
相同)
create table users (
user_name varchar(32) not null primary key,
user_pass varchar(64) not null,
-- Add more attributes as needed
);
create table user_roles (
user_name varchar(32),
role_name varchar(32),
primary key (user_name, role_name)
);
2. 宣告你的資源
接著,修改 $CATALINA_BASE/conf/server.xml
以根據你的 DataSource
及其架構建立 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.DataSourceUserDatabaseFactory"
dataSourceName="jdbc/authority" readonly="false"
userTable="users" userNameCol="user_name" userCredCol="user_pass"
userRoleTable="user_roles" roleNameCol="role_name"
roleTable="roles" groupTable="groups" userGroupTable="user_groups"
groupRoleTable="group_roles" groupNameCol="group_name" />
dataSourceName
屬性是 UserDatabase
後端的 DataSource
的 JNDI 名稱。它必須在與 UserDatabase
相同的 JNDI Context
中宣告。請參閱 DataSource
資源 文件以取得進一步說明。
readonly
屬性是選用的,如果未提供,則預設為 true
。如果資料庫可寫入,則透過 Tomcat 管理對 UserDatabase
所做的變更可以使用 save
操作持續到資料庫中。
或者,也可以直接對後端資料庫進行變更。
3. 資源設定
屬性 | 說明 |
---|---|
dataSourceName |
此 UserDatabase 的 JNDI JDBC DataSource 名稱。 |
groupNameCol |
「群組」、「群組角色」和「使用者群組」表格中包含群組名稱的欄位名稱。 |
groupRoleTable |
「群組角色」表格的名稱,其中必須包含由 |
groupTable |
「群組」表格的名稱,其中必須包含由 |
readonly |
如果將此設定為 |
roleAndGroupDescriptionCol |
「角色」和「群組」表格中包含角色和群組說明的欄位名稱。 |
roleNameCol |
「角色」、「使用者角色」和「群組角色」表格中包含指派給對應使用者的角色名稱的欄位名稱。 此屬性在大部分設定中是必需的。請參閱關聯領域的 allRolesMode 屬性,以了解在罕見情況下可以省略此屬性的情況。 |
roleTable |
「角色」表格的名稱,其中必須包含由 |
userCredCol |
「使用者」表格中包含使用者憑證(例如密碼)的欄位名稱。如果指定了 |
userGroupTable |
「使用者群組」表格的名稱,其中必須包含由 |
userNameCol |
「使用者」、「使用者群組」和「使用者角色」表格中包含使用者使用者名稱的欄位名稱。 |
userFullNameCol |
「使用者」表格中包含使用者全名的欄位名稱。 |
userRoleTable |
「使用者角色」表格的名稱,其中必須包含由 此屬性在大部分設定中是必需的。請參閱關聯領域的 allRolesMode 屬性,以了解在罕見情況下可以省略此屬性的情況。 |
userTable |
「使用者」表格的名稱,其中必須包含由 |
4. 設定領域
設定 UserDatabase Realm 以使用此資源,如 Realm 設定文件 中所述。
Jakarta Mail 會話
0. 簡介
在許多 Web 應用程式中,傳送電子郵件訊息是系統功能的必要部分。Jakarta Mail API 讓這個程序相對簡單,但需要許多設定詳細資料,而客戶端應用程式必須知道這些資料(包括用於傳送訊息的 SMTP 主機名稱)。
Tomcat 包含一個標準資源工廠,它會為您建立 jakarta.mail.Session
會話執行個體,並已設定好連線到 SMTP 伺服器。這樣一來,應用程式就能完全不受電子郵件伺服器設定環境變更的影響,它只要在需要時要求並接收預先設定好的會話即可。
以下是執行此操作所需的步驟。
1. 宣告您的資源需求
您應該做的第一件事是修改 Web 應用程式部署描述檔(/WEB-INF/web.xml
)以宣告您將在其中查詢預先設定好會話的 JNDI 名稱。根據慣例,所有此類名稱都應該解析為 mail
子內容(相對於標準 java:comp/env
命名內容,它是所有提供的資源工廠的根目錄)。典型的 web.xml
項目可能如下所示
<resource-ref>
<description>
Resource reference to a factory for jakarta.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>
jakarta.mail.Session
</res-type>
<res-auth>
Container
</res-auth>
</resource-ref>
警告 - 請務必尊重 Web 應用程式部署描述符的 DTD 所要求的元素順序!請參閱 Servlet 規格 以取得詳細資訊。
2. 編寫應用程式使用此資源的程式碼
此資源參照的典型用法可能如下所示
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);
請注意,應用程式使用與在 Web 應用程式部署描述檔中宣告的相同資源參照名稱。這會與在 <Context>
元素中為 Web 應用程式設定的資源工廠進行比對,如下所述。
3. 設定 Tomcat 的資源工廠
若要設定 Tomcat 的資源工廠,請將類似這樣的元素新增到此 Web 應用程式的 <Context>
元素。
<Context ...>
...
<Resource name="mail/Session" auth="Container"
type="jakarta.mail.Session"
mail.smtp.host="localhost"/>
...
</Context>
請注意,資源名稱(在此為 mail/Session
)必須與在 Web 應用程式部署描述符中指定的數值相符。自訂 mail.smtp.host
參數的數值,以指向提供 SMTP 服務給您網路的伺服器。
其他資源屬性和數值將轉換為屬性和數值,並作為 java.util.Properties
資訊的其中一部分傳遞給 jakarta.mail.Session.getInstance(java.util.Properties)
。除了 Jakarta Mail 規格附錄 A 中定義的屬性之外,個別供應商也可能支援其他屬性。
如果資源已使用 password
屬性和 mail.smtp.user
或 mail.user
屬性進行組態,則 Tomcat 的資源工廠將組態並將 jakarta.mail.Authenticator
新增至郵件工作階段。
4. 安裝 Jakarta Mail API
解開封裝發行套件並將 jakarta.mail-api-2.1.0.jar 放入 $CATALINA_HOME/lib,以便在郵件工作階段資源初始化期間提供給 Tomcat 使用。注意:將此 jar 放入 $CATALINA_HOME/lib 和 Web 應用程式的 lib 資料夾中會導致錯誤,因此請確保只將其放在 $CATALINA_HOME/lib 位置。
5. 安裝相容的實作
選擇並下載相容的實作。
解開封裝實作並將 jar 檔案放入 $CATALINA_HOME/lib。
注意:其他實作可能可用
6. 重新啟動 Tomcat
若要讓 Tomcat 能看到其他 JAR,必須重新啟動 Tomcat 執行個體。
範例應用程式
Tomcat 附帶的 /examples
應用程式包含使用此資源工廠的範例。可透過「JSP 範例」連結存取。實際傳送郵件訊息的 servlet 的原始程式碼位於 /WEB-INF/classes/SendMailServlet.java
。
警告 - 預設組態假設在 localhost
上有一個 SMTP 伺服器在連接埠 25 上列出。如果不是這種情況,請編輯此 Web 應用程式的 <Context>
元素,並修改 mail.smtp.host
參數的參數值,使其為您網路上的 SMTP 伺服器的主機名稱。
JDBC 資料來源
0. 簡介
許多 Web 應用程式需要透過 JDBC 驅動程式存取資料庫,以支援該應用程式所需的運作。Jakarta EE Platform Specification 要求 Jakarta EE 應用程式伺服器提供一個 DataSource 實作(也就是 JDBC 連線的連線池)以達到此目的。Tomcat 提供完全相同的支援,因此您使用此服務在 Tomcat 上開發的資料庫應用程式,可以在任何 Jakarta EE 伺服器上不變更地執行。
有關 JDBC 的資訊,您應參閱下列內容
- http://www.oracle.com/technetwork/java/javase/jdbc/index.html - Java 資料庫連線資訊首頁。
- http://java.sun.com/j2se/1.3/docs/guide/jdbc/spec2/jdbc2.1.frame.html - JDBC 2.1 API 規格。
- http://java.sun.com/products/jdbc/jdbc20.stdext.pdf - JDBC 2.0 標準延伸 API(包括
javax.sql.DataSource
API)。此套件現在稱為「JDBC 選用套件」。 - https://jakarta.ee/specifications/platform/9/ - Jakarta EE Platform Specification(涵蓋所有 Jakarta EE 平台必須提供給應用程式的 JDBC 設施)。
注意 - Tomcat 中的預設資料來源支援是基於 Commons 專案中的 DBCP 2 連線池。不過,您可以撰寫自己的自訂資源工廠,來使用任何其他實作 javax.sql.DataSource
的連線池,如 下方 所述。
1. 安裝您的 JDBC 驅動程式
使用 JDBC 資料來源 JNDI 資源工廠需要您提供適當的 JDBC 驅動程式,供 Tomcat 內部類別和您的 Web 應用程式使用。最簡單的方法是將驅動程式的 JAR 檔案安裝到 $CATALINA_HOME/lib
目錄中,這會讓資源工廠和您的應用程式都能使用該驅動程式。
2. 宣告您的資源需求
接著,修改 Web 應用程式部署描述子 (/WEB-INF/web.xml
) 來宣告您將用來查詢預先設定資料來源的 JNDI 名稱。依慣例,所有此類名稱都應解析為 jdbc
子內容(相對於標準 java:comp/env
命名內容,這是所有提供的資源工廠的根)。典型的 web.xml
項目可能如下所示
<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>
configuration 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 應用程式部署描述符的 DTD 所要求的元素順序!請參閱 Servlet 規格 以取得詳細資訊。
3. 編寫您的應用程式使用此資源的程式碼
此資源參照的典型用法可能如下所示
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();
請注意,應用程式使用與在 Web 應用程式部署描述檔中宣告的相同資源參照名稱。這會與在 <Context>
元素中為 Web 應用程式設定的資源工廠進行比對,如下所述。
4. 設定 Tomcat 的資源工廠
若要設定 Tomcat 的資源工廠,請將類似這樣的元素新增到 Web 應用程式的 <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 應用程式部署描述符中指定的數值相符。
此範例假設您使用的是 HypersonicSQL 資料庫 JDBC 驅動程式。請自訂 driverClassName
和 driverName
參數,以符合您實際資料庫的 JDBC 驅動程式和連線網址。
Tomcat 的標準資料來源資源工廠(org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory
)的設定屬性如下
- driverClassName - 要使用的 JDBC 驅動程式的完整 Java 類別名稱。
- username - 要傳遞給 JDBC 驅動程式的資料庫使用者名稱。
- password - 要傳遞給 JDBC 驅動程式的資料庫密碼。
- url - 要傳遞給 JDBC 驅動程式的連線網址。(為了向後相容性,屬性
driverName
也被辨識。) - initialSize - 池初始化期間將在池中建立的初始連線數。預設值:0
- maxTotal - 可以同時從此池配置的最大連線數。預設值:8
- minIdle - 同時會閒置在此池中的最小連線數。預設值:0
- maxIdle - 同時可以閒置在此池中的最大連線數。預設值:8
- maxWaitMillis - 池會等待(當沒有可用連線時)連線返回的最大毫秒數,然後擲回例外。預設值:-1(無限)
一些額外的屬性會處理連線驗證
- validationQuery - 池可以在將連線傳回應用程式之前,使用此 SQL 查詢來驗證連線。如果指定,此查詢必須是會傳回至少一列的 SQL SELECT 陳述式。
- validationQueryTimeout - 驗證查詢傳回的逾時時間(以秒為單位)。預設值:-1(無限)
- testOnBorrow - true 或 false:每次從池中借用連線時,是否應使用驗證查詢來驗證連線。預設值:true
- testOnReturn - true 或 false:每次將連線傳回池時,是否應使用驗證查詢來驗證連線。預設值:false
可選擇的驅逐執行緒負責縮小池,方法是移除閒置時間過長的連線。驅逐執行緒不尊重 minIdle
。請注意,如果您只想讓池根據已設定的 maxIdle
屬性縮小,則不需要啟動驅逐執行緒。
驅逐程式預設為停用,可以使用下列屬性進行設定
- timeBetweenEvictionRunsMillis - 連續執行驅逐程式之間的毫秒數。預設值:-1(停用)
- numTestsPerEvictionRun - 驅逐程式在每次執行期間,會檢查連線閒置狀態的連線數。預設值:3
- minEvictableIdleTimeMillis - 連線在池中閒置的毫秒數,超過此時間後,驅逐程式會將連線從池中移除。預設值:30*60*1000(30 分鐘)
- testWhileIdle - true 或 false:是否應由驅逐程式執行緒使用驗證查詢來驗證連線,同時在池中閒置。預設值:false
另一個選用功能是移除放棄的連線。如果應用程式長時間未將連線傳回池中,則該連線會稱為放棄的連線。池可以自動關閉此類連線,並將其從池中移除。這是因應應用程式造成連線外洩的解決方法。
放棄功能預設為停用,可以使用下列屬性進行設定
- removeAbandonedOnBorrow - true 或 false:在借用連線時,是否從池中移除放棄的連線。預設值:false
- removeAbandonedOnMaintenance - true 或 false:在池維護期間,是否從池中移除放棄的連線。預設值:false
- removeAbandonedTimeout - 借用的連線在經過多少秒後,會假設為放棄的連線。預設值:300
- logAbandoned - true 或 false:是否記錄放棄陳述式或連線的應用程式程式碼的堆疊追蹤。這會增加嚴重的負擔。預設值:false
最後,有各種屬性可以進一步微調池的行為
- defaultAutoCommit - true 或 false:此池建立的連線的預設自動提交狀態。預設值:true
- defaultReadOnly - true 或 false:此池建立的連線的預設唯讀狀態。預設值:false
- defaultTransactionIsolation - 這會設定預設的交易隔離層級。可以是
NONE
、READ_COMMITTED
、READ_UNCOMMITTED
、REPEATABLE_READ
、SERIALIZABLE
之一。預設值:未設定預設值 - poolPreparedStatements - true 或 false:是否要將 PreparedStatements 和 CallableStatements 加入池中。預設值:false
- maxOpenPreparedStatements - 可以從陳述式池中同時配置的開啟陳述式最大數。預設值:-1(無限制)
- defaultCatalog - 預設目錄的名稱。預設值:未設定
- connectionInitSqls - 在建立連線後執行一次的 SQL 陳述式清單。使用分號 (
;
) 分隔多個陳述式。預設值:無陳述式 - connectionProperties - 傳遞給驅動程式以建立連線的驅動程式特定屬性清單。每個屬性以
name=value
表示,多個屬性使用分號 (;
) 分隔。預設值:無屬性 - accessToUnderlyingConnectionAllowed - true 或 false:是否允許存取基礎連線。預設值:false
如需更多詳細資料,請參閱 Commons DBCP 2 文件。
新增自訂資源工廠
如果沒有任何標準資源工廠符合您的需求,您可以撰寫自己的工廠並將其整合到 Tomcat 中,然後在 Web 應用程式的 <Context>
元素中設定使用此工廠。在以下範例中,我們將建立一個工廠,它只知道如何從上述 通用 JavaBean 資源 範例中建立 com.mycompany.MyBean
bean。
1. 撰寫資源工廠類別
您必須撰寫一個實作 JNDI 服務提供者 javax.naming.spi.ObjectFactory
介面的類別。每當您的 Web 應用程式在與此工廠繫結的內容項目上呼叫 lookup()
時(假設工廠設定為 singleton="false"
),就會呼叫 getObjectInstance()
方法,並傳入下列引數
- 物件 obj - 包含可於建立物件時使用的位置或參考資訊(可能為 null)的物件。對於 Tomcat,這將永遠是
javax.naming.Reference
型別的物件,其中包含此工廠類別的名稱,以及用於建立要傳回的物件的設定內容(來自 Web 應用程式的<Context>
)。 - 名稱 name - 此工廠相對於
nameCtx
繫結的名稱,或如果未指定名稱,則為null
。 - 內容 nameCtx -
name
參數相對於其指定的內容,或如果name
相對於預設初始內容,則為null
。 - 雜湊表環境 environment - 用於建立此物件的環境(可能為 null)。這通常在 Tomcat 物件工廠中會被忽略。
若要建立一個知道如何產生 MyBean
執行個體的資源工廠,您可以建立一個類別,如下所示
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 name2, 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);
}
}
在此範例中,我們無條件建立 com.mycompany.MyBean
類別的新執行個體,並根據設定此工廠的 <ResourceParams>
元素中包含的參數來填入其內容(請見下方)。您應該注意,任何名為 factory
的參數都應該略過 - 該參數用於指定工廠類別本身的名稱(在本例中為 com.mycompany.MyBeanFactory
),而不是要設定的 bean 的內容。
如需有關 ObjectFactory
的更多資訊,請參閱 JNDI 服務提供者介面 (SPI) 規格。
您需要針對包含 $CATALINA_HOME/lib
目錄中所有 JAR 檔案的類別路徑編譯此類別。完成後,將未解壓的工廠類別(和對應的 bean 類別)放置在 $CATALINA_HOME/lib
下,或放置在 $CATALINA_HOME/lib
內的 JAR 檔案中。這樣,Catalina 內部資源和您的 Web 應用程式都可以看到所需的類別檔案。
2. 宣告您的資源需求
接著,修改您的 Web 應用程式部署描述符 (/WEB-INF/web.xml
) 以宣告您將在該宣告中要求此 Bean 的新實例的 JNDI 名稱。最簡單的方法是使用 <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 應用程式部署描述符的 DTD 所要求的元素順序!請參閱 Servlet 規格 以取得詳細資訊。
3. 編寫您的應用程式使用此資源的程式碼
此資源環境參考的典型用法可能如下所示
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());
4. 設定 Tomcat 的資源工廠
若要設定 Tomcat 的資源工廠,請將類似這樣的元素新增到此 Web 應用程式的 <Context>
元素。
<Context ...>
...
<Resource name="bean/MyBeanFactory" auth="Container"
type="com.mycompany.MyBean"
factory="com.mycompany.MyBeanFactory"
singleton="false"
bar="23"/>
...
</Context>
請注意資源名稱 (在此為 bean/MyBeanFactory
) 必須與 Web 應用程式部署描述符中指定的數值相符。我們也正在初始化 bar
屬性的值,這將導致在傳回新的 Bean 之前呼叫 setBar(23)
。由於我們沒有初始化 foo
屬性 (儘管我們可以初始化),因此 Bean 將包含由其建構函式設定的任何預設值。
您還會注意到,從應用程式開發人員的角度來看,資源環境參考的宣告,以及用於要求新執行個體的程式設計,與用於 通用 JavaBean 資源 範例的方法相同。這說明了使用 JNDI 資源封裝功能的其中一個優點 - 只要您維護相容的 API,您就可以變更基礎實作,而無需修改使用這些資源的應用程式。