简介

Tomcat 为在其下运行的每个web应用程序提供一个 JNDI InitialContext 实现实例, 其方式与 Jakarta EE 应用程序服务器提供的实例兼容。 Jakarta EE 标准在 /WEB-INF/web.xml 文件中提供了一组标准元素,用于引用/定义资源。

有关 JNDI 编程 API 和 Jakarta EE 服务器支持的功能的更多信息, Tomcat 为其提供的服务模拟了这些功能,请参阅以下规范:

web.xml 配置

在web应用程序的部署描述符(/WEB-INF/web.xml)中可使用以下元素来定义资源:

  • <env-entry> - 环境条目,单值参数,可用于配置应用程序的运行方式。

  • <resource-ref> - 资源引用,通常是资源的对象工厂,如 JDBC DataSource、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

"组角色"表的名称,必须包含以 groupNameColroleNameCol 属性命名的列。

groupTable

"组"表的名称,必须包含由 groupNameCol 属性命名的列。

readonly

如果设置为 true,则可通过使用`save`方法将对 UserDatabase 的更改持久化到 DataSource。默认值为 true

roleAndGroupDescriptionCol

"角色"和 "组"表中包含角色和组描述的列的名称。

roleNameCol

"角色"、"用户角色"和"组角色"表中包含分配给相应用户的角色名称的列的名称。 大多数配置都需要此属性。在极少数情况下,该属性可以省略,请参阅相关领域的 allRolesMode 属性。

roleTable

"角色"表的名称,必须包含由 roleNameCol 属性命名的列。

userCredCol

"用户"表中包含用户凭据(即密码)的列的名称。 如果指定了凭证处理程序(CredentialHandler),该组件将假定密码已按指定算法编码。 否则,密码将被视为明文。

userGroupTable

"用户组"表的名称,必须包含以 userNameColgroupNameCol 属性命名的列。

userNameCol

"用户"、"用户组"和"用户角色"表中包含用户用户名的列的名称。

userFullNameCol

"用户"表中包含用户全名的列名。

userRoleTable

"用户角色"表的名称,必须包含以 userNameColroleNameCol 属性命名的列。 大多数配置都需要此属性。在极少数情况下,该属性可以省略,请参阅相关领域的 `allRolesMode `属性。

userTable

"users"表的名称,必须包含由 userNameColuserCredCol 属性命名的列。

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 位置。

5. 安装兼容的实现

选择并 下载兼容的实现

解压实现并将 jar 文件放入 $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 的信息,请参考以下内容:

注意 - 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 驱动程序。 请自定义 driverClassNamedriverName 参数,以匹配实际数据库的 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 - 设置默认事务隔离级别。可以是 NONEREAD_COMMITTEDREAD_UNCOMMITTEDREPEATABLE_READSERIALIZABLE 之一。默认:未设置默认值

  • poolPreparedStatements - true 或 false:是否汇集 PreparedStatementsCallableStatements。默认值: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,就可以更改底层实现,而不必修改使用资源的应用程序。