简介
Tomcat 为在其下运行的每个web应用程序提供一个 JNDI InitialContext 实现实例,
其方式与 Jakarta EE 应用程序服务器提供的实例兼容。
Jakarta EE 标准在 /WEB-INF/web.xml
文件中提供了一组标准元素,用于引用/定义资源。
有关 JNDI 编程 API 和 Jakarta EE 服务器支持的功能的更多信息, Tomcat 为其提供的服务模拟了这些功能,请参阅以下规范:
-
Java 命名和目录接口(JNDI)(包含在 JDK 1.4 以后的版本中)
-
Jakarta EE 平台规范(特别请参阅第 5 章 "命名")。
web.xml 配置
在web应用程序的部署描述符(/WEB-INF/web.xml
)中可使用以下元素来定义资源:
-
<env-entry>
- 环境条目,单值参数,可用于配置应用程序的运行方式。 -
<resource-ref>
- 资源引用,通常是资源的对象工厂,如 JDBCDataSource
、Jakarta Mail `Session`或配置到 Tomcat 的自定义对象工厂。 -
<resource-env-ref>
- 资源环境引用,是 Servlet 2.4 中添加的`resource-ref资源引用`的新变体,对于不需要身份验证信息的资源,其配置更为简单。
如果 Tomcat 能够识别用于创建资源的适当资源工厂,并且不需要进一步的配置信息,
Tomcat 将使用 /WEB-INF/web.xml
中的信息创建资源。
Tomcat 为 JNDI 资源提供了许多不能在 web.xml 中指定的 Tomcat 特定选项。
这些选项包括:closeMethod
(当网络应用程序停止时能更快地清理 JNDI 资源)和
singleton
(控制每次 JNDI 查询是否创建资源的新实例)。
要使用这些配置选项,必须在网络应用程序的
<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
暴露给网络应用的标量环境条目配置名称和值(相当于在网络应用部署描述符中包含<env-entry>
元素)。 -
<Resource> - 配置应用程序可用资源的名称和数据类型(相当于在网络应用程序部署描述符中包含
<resource-ref>
元素)。 -
<ResourceLink> - 添加指向全局 JNDI 上下文中定义的资源的链接。使用资源链接可让网络应用访问在 <Server> 元素的 <GlobalNamingResources> 子元素中定义的资源。
-
<Transaction> - 添加一个资源工厂,用于实例化
java:comp/UserTransaction
中的 UserTransaction 对象实例。
任何数量的这些元素都可以嵌套在 <Context>
元素中,并且只与该特定网络应用相关联。
如果资源已在 <Context>
元素中定义,则无需在 /WEB-INF/web.xml
中定义该资源。
但建议在 /WEB-INF/web.xml
中保留条目,以记录网络应用的资源需求。
如果网络应用程序部署描述符 (/WEB-INF/web.xml
) 中的 <env-entry>
元素
和作为网络应用程序 <Context>
元素一部分的 <Environment>
元素中定义了相同的资源名称,
则只有在相应 <Environment>
元素允许的情况下
(通过将`override覆盖`属性设置为 "true"),部署描述符中的值才会优先。
全局配置
Tomcat 为整个服务器维护一个单独的全局资源命名空间。
这些资源在 $CATALINA_BASE/conf/server.xml
的 <GlobalNamingResources>
元素中配置。\
可以通过使用 <ResourceLink>
将这些资源包含在每个网络应用上下文中,从而将其公开给网络应用。
如果使用 <ResourceLink>
定义了资源,则无需在 /WEB-INF/web.xml
中定义该资源。
不过,建议在 /WEB-INF/web.xml
中保留条目,以记录网络应用的资源需求。
使用资源
InitialContext
在网络应用程序初始部署时进行配置,并提供给网络应用程序组件(只读访问)。
所有已配置的条目和资源都放在 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 包含一系列标准资源工厂,它们可以为网络应用程序提供服务,
同时还能灵活配置(通过 <Context>
元素),而无需修改网络应用程序或部署描述符。
以下各小节详细介绍了标准资源工厂的配置和使用。
有关如何使用 Tomcat 创建、安装、配置和使用自己的自定义资源工厂类的信息, 请参阅 添加自定义资源工厂。
注意 - 在标准资源工厂中,只有 "JDBC 数据源 "和 "用户事务 "工厂被强制要求在其他平台上可用, 而且只有当该平台实现了 Jakarta EE 规范时才需要使用。 所有其他标准资源工厂以及自己编写的自定义资源工厂都是 Tomcat 特有的,不能假定它们在其他容器上可用。
通用 JavaBean 资源
0. 简介
该资源工厂可用于创建符合标准 JavaBean 命名约定的任何 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-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>
警告:请务必遵守网络应用程序部署描述符 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())
bean.getBar());
4. 配置 Tomcat 的资源工厂
要配置 Tomcat 的资源工厂,请在此网络应用程序的 <Context>
元素中添加如下元素。
<Context ...>
...
<Resource name="bean/MyBeanFactory" auth="Container"
type="com.mycompany.MyBean"
factory="org.apache.naming.factory.BeanFactory"
bar="23"/>
...
</Context>
请注意,资源名称(此处为 bean/MyBeanFactory
)必须与网络应用程序部署描述符中指定的值相匹配。
还初始化了 bar
属性的值,这将导致在返回新 Bean 之前调用 setBar(23)
。
由于没有初始化 foo 属性(尽管可以这样做),因此 Bean 将包含其构造函数设置的任何默认值。
如果 bean 属性的类型是`String`,BeanFactory 将使用提供的属性值调用属性设置器。 如果 bean 属性类型是基元或基元包装器,BeanFactory 将把值转换为适当的基元或基元包装器, 然后在调用设置器时使用该值。有些 Bean 属性的类型无法自动从`String`转换。 如果 Bean 提供了一个同名的设置器,且该设置器使用`String`,BeanFactory 将尝试使用该设置器。 如果 BeanFactory 无法使用该值或执行适当的转换,那么设置该属性将失败并出现 NamingException 异常。
作为一项安全加固措施,Tomcat 早期版本中的 forceString
属性已被移除。
内存用户数据库资源
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 运行用户的默认文件权限。
确保这些权限适当,以维护安装的安全性。
如果在 "域 "中引用,默认情况下,UserDatabase 将监控`pathname路径名`的更改,
并在最后修改时间发生变化时重新加载文件。可以通过将 watchSource
属性设置为 false
来禁用此功能。
3. 配置域
如 Realm 配置文档所述, 配置用户数据库 Realm 以使用此资源。
数据源用户数据库资源
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
属性是`DataSource数据源`的 JNDI 名称,该数据源将作为 UserDatabase
的后端。
必须在与 UserDatabase
相同的 JNDI `Context上下文`中声明。
有关进一步说明,请参阅https://tomcat.apache.org/tomcat-10.1-doc/jndi-resources-howto.html#JDBC_Data_Sources[数据源]资源文档。
readonly
属性是可选的,如果没有提供,默认为 true
。
如果数据库是可写的,那么通过 Tomcat 管理对 UserDatabase
所做的更改可使用`save保存`操作持久化到数据库中。
或者,也可以直接对后台数据库进行更改。
3. 资源配置
属性 | 描述 |
---|---|
dataSourceName |
此用户数据库的 JNDI JDBC 数据源名称。 |
groupNameCol |
"组"、"组角色 "和 "用户组 "表中包含组名的列的名称。 |
groupRoleTable |
"组角色"表的名称,必须包含以 |
groupTable |
"组"表的名称,必须包含由 |
readonly |
如果设置为 |
roleAndGroupDescriptionCol |
"角色"和 "组"表中包含角色和组描述的列的名称。 |
roleNameCol |
"角色"、"用户角色"和"组角色"表中包含分配给相应用户的角色名称的列的名称。
大多数配置都需要此属性。在极少数情况下,该属性可以省略,请参阅相关领域的 |
roleTable |
"角色"表的名称,必须包含由 |
userCredCol |
"用户"表中包含用户凭据(即密码)的列的名称。
如果指定了凭证处理程序( |
userGroupTable |
"用户组"表的名称,必须包含以 |
userNameCol |
"用户"、"用户组"和"用户角色"表中包含用户用户名的列的名称。 |
userFullNameCol |
"用户"表中包含用户全名的列名。 |
userRoleTable |
"用户角色"表的名称,必须包含以 |
userTable |
"users"表的名称,必须包含由 |
4. 配置境界
按照 Realm 配置文档中的说明, 配置 UserDatabase Realm 以使用该资源。
Jakarta Mail Sessions
0. 简介
在许多网络应用程序中,发送电子邮件是系统功能的必要组成部分。 Jakarta 邮件 API 使这一过程相对简单, 但要求客户端应用程序必须了解许多配置细节(包括用于发送邮件的 SMTP 主机名)。
Tomcat 包含一个标准资源工厂,可为创建 jakarta.mail.Session
会话实例,这些实例已配置为连接到 SMTP 服务器。
这样,应用程序就完全不受电子邮件服务器配置环境变化的影响,只需在需要时请求并接收一个预先配置好的会话即可。
具体步骤如下。
1. 声明资源需求
首先要修改网络应用程序部署描述符(/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>
警告:请务必遵守网络应用程序部署描述符 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);
请注意,应用程序使用的资源引用名称与网络应用程序部署描述符中声明的资源引用名称相同。
如下所述,这将与网络应用程序 <Context>
元素中配置的资源工厂相匹配。
3. 配置 Tomcat 的资源工厂
要配置 Tomcat 的资源工厂,请在该网络应用程序的 <Context>
元素中添加如下元素。
<Context ...>
...
<Resource name="mail/Session" auth="Container"
type="jakarta.mail.Session"
mail.smtp.host="localhost"/>
...
</Context>
请注意,资源名称(此处为 mail/Session
)必须与网络应用程序部署描述符中指定的值相匹配。
自定义 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 位置。
6. 重启 Tomcat
为使 Tomcat 能够看到附加的 JAR,有必要重新启动 Tomcat 实例。
示例应用程序
Tomcat 随附的 /examples
应用程序包含一个使用该资源工厂的示例。可通过 "JSP 示例" 链接访问该示例。
实际发送邮件信息的 servlet 源代码位于 /WEB-INF/classes/SendMailServlet.java
中。
警告:默认配置假定本地主机上的 25 端口有一个 SMTP 服务器。
如果不是这种情况,请编辑此 Web 应用程序的 <Context>
元素,
并将 mail.smtp.host
参数的参数值修改为网络上 SMTP 服务器的主机名。
JDBC 数据源
0. 简介
许多网络应用程序需要通过 JDBC 驱动程序访问数据库,以支持应用程序所需的功能。 Jakarta EE 平台规范要求 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 平台规范》(涵盖所有 Jakarta EE 平台必须向应用程序提供的 JDBC 设施)。
注意 - Tomcat 的默认数据源支持基于 Commons 项目的 DBCP 2 连接池。
不过,也可以通过编写自己的自定义资源工厂,使用任何其他实现 javax.sql.DataSource
的连接池,如下所述。
1. 安装 JDBC 驱动程序
使用 JDBC 数据源 JNDI 资源工厂需要向 Tomcat 内部类和 Web 应用程序提供适当的 JDBC 驱动程序。
最简单的方法是将驱动程序的 JAR 文件安装到 $CATALINA_HOME/lib
目录中,这样资源工厂和应用程序都可以使用驱动程序。
2. 声明资源需求
接下来,修改网络应用程序部署描述符 (/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>
警告:请务必遵守网络应用程序部署描述符 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();
请注意,应用程序使用的资源引用名称与网络应用程序部署描述符中声明的资源引用名称相同。
如下所述,这将与网络应用程序 <Context>
元素中配置的资源工厂相匹配。
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 驱动程序和连接 URL。
Tomcat 标准数据源资源工厂(org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory
)的配置属性如下:
-
driverClassName - 要使用的 JDBC 驱动程序的 Java 全限定类名。
-
username - 要传递给 JDBC 驱动程序的数据库用户名。
-
password - 将传递给 JDBC 驱动程序的数据库密码。
-
url - 将传递给 JDBC 驱动程序的连接 URL。(为了向后兼容,属性
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 中,
然后在网络应用程序的 <Context>
元素中配置该工厂的使用。
在下面的示例中,将创建一个只知道如何从上面的
通用 JavaBean 资源
示例中创建 com.mycompany.MyBean
Bean 的工厂。
1. 编写资源工厂类
必须编写一个实现 JNDI 服务提供商 javax.naming.spi.ObjectFactory
接口的类。
每次网络应用程序在绑定到该工厂的上下文条目上调用 lookup()
(假设工厂的配置为 singleton="false"
)时,
都会调用 getObjectInstance()
方法,该方法的参数如下:
-
Object obj - 包含位置或引用信息的对象(可能为空),可用于创建对象。对于 Tomcat,这将始终是
javax.naming.Reference
类型的对象,其中包含该工厂类的类名,以及用于创建要返回的对象的配置属性(来自网络应用程序的<Context>
)。 -
Name name - 与
nameCtx
相对应的工厂名称,如果未指定名称,则为`null空`。 -
Context nameCtx -
name名称`参数指定的相对上下文,如果`name名称`相对于默认初始上下文,则为`null空
。 -
Hashtable environment - 用于创建该对象的环境(可能为空)。在 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 内部资源和网络应用都能看到所需的类文件。
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>
警告:请务必遵守网络应用程序部署描述符 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 的资源工厂,请在此网络应用程序的 <Context>
元素中添加如下元素。
<Context ...>
...
<Resource name="bean/MyBeanFactory" auth="Container"
type="com.mycompany.MyBean"
factory="com.mycompany.MyBeanFactory"
singleton="false"
bar="23"/>
...
</Context>
请注意,资源名称(此处为 bean/MyBeanFactory
)必须与网络应用程序部署描述符中指定的值相匹配。
我们还初始化了 bar
属性的值,这将导致在返回新 Bean 之前调用 setBar(23)
。
由于我们没有初始化 foo
属性(尽管我们可以这样做),因此 Bean 将包含其构造函数设置的任何默认值。
还会注意到,从应用程序开发人员的角度来看,资源环境引用的声明和用于请求新实例的编程与 通用 JavaBean 资源示例中使用的方法完全相同。这说明了使用 JNDI 资源封装功能的优势之一-- 只要保持兼容的 API,就可以更改底层实现,而不必修改使用资源的应用程序。