JNDI Resources How-To

Table of Contents

Introduction

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

请参阅以下规范,以获取有关用于JNDI的编程API以及Tomcat为其提供的服务所仿真的Java Enterprise Edition(Java EE)服务器支持的功能的更多信息:

web.xml configuration

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

  • <env-entry> -环境条目,一个单值参数,可用于配置应用程序的运行方式.
  • <resource-ref> -资源引用,通常是对象工厂的资源,例如JDBC DataSource ,JavaMail Session或配置到Tomcat中的自定义对象工厂.
  • <resource-env-ref> -资源环境参考,是Servlet 2.4中添加的resource-ref的新变体,对于不需要身份验证信息的资源,它更易于配置.

如果Tomcat能够标识用于创建资源的适当资源工厂,并且不需要其他配置信息,则Tomcat将使用/WEB-INF/web.xml的信息来创建资源.

Tomcat为无法在web.xml中指定的JNDI资源提供了许多Tomcat特定的选项. 其中包括closeMethod ,它可以在Web应用程序停止时更快地清理JNDI资源,以及singleton控制是否为每个JNDI查找创建资源的新实例. 要使用这些配置选项,必须在Web应用程序的<Context>元素或$CATALINA_BASE/conf/server.xml<GlobalNamingResources>元素中指定资源.

context.xml configuration

如果Tomcat无法识别适当的资源工厂和/或需要其他配置信息,则必须指定其他特定于Tomcat的配置,然后Tomcat才能创建资源. 在<Context>元素中输入了Tomcat特定的资源配置,该元素可以在$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应用程序可以访问在<Server>元素的<GlobalNamingResources>子元素中定义的资源.
  • <Transaction> -添加资源工厂用于实例化java:comp/UserTransaction可用的UserTransaction对象实例.

这些元素中的任何数量都可以嵌套在<Context>元素内,并且仅与该特定的Web应用程序关联.

如果在<Context>元素中定义了资源,则不必在/WEB-INF/web.xml定义该资源. 但是,建议将该条目保留在/WEB-INF/web.xml以记录Web应用程序的资源要求.

在其中为Web应用程序部署描述符( /WEB-INF/web.xml )中的<Environment> <env-entry>元素和作为<Context>元素一部分的<Environment>元素中包含的<env-entry>元素定义了相同的资源名称的情况Web应用程序, 当相应的<Environment>元素允许时(通过将override属性设置为" true"),部署描述符中的值优先.

Global configuration

Tomcat为整个服务器维护一个单独的全局资源命名空间. 这些是在$CATALINA_BASE/conf/server.xml<GlobalNamingResources>元素中$CATALINA_BASE/conf/server.xml . 您可以使用<ResourceLink>将这些资源公开给Web应用程序,以将其包含在每个Web应用程序上下文中.

如果使用<ResourceLink>定义了资源 ,则不必在/WEB-INF/web.xml定义该资源. 但是,建议将该条目保留在/WEB-INF/web.xml以记录Web应用程序的资源要求.

Using resources

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 Standard Resource Factories

Tomcat包括一系列标准资源工厂,这些工厂可以为Web应用程序提供服务,但在不修改Web应用程序或部署描述符的情况<Context> (通过<Context>元素)为您提供了配置灵活性. 以下每个小节详细介绍了标准资源工厂的配置和使用.

有关如何在Tomcat中创建,安装,配置和使用您自己的自定义资源工厂类的信息,请参见添加自定义资源工厂 .

–在标准资源工厂中,只有" JDBC数据源"和"用户事务"工厂被强制在其他平台上可用,然后只有在平台实现Java Enterprise Edition(Java EE)规范时才需要它们. 所有其他标准资源工厂,以及您自己编写的自定义资源工厂,都是特定于Tomcat的,不能假定在其他容器上可用.

Generic JavaBean Resources

0. Introduction

This resource factory can be used to create objects of any Java class that conforms to standard JavaBeans naming conventions (i.e. it has a zero-arguments constructor, and has property setters that conform to the setFoo() naming pattern. The resource factory will only create a new instance of the appropriate bean class every time a lookup() for this entry is made if the singleton attribute of the factory is set to false.

下面介绍了使用此功能所需的步骤.

1. Create Your JavaBean Class

创建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. Declare Your Resource Requirements

接下来,修改Web应用程序部署描述符( /WEB-INF/web.xml ),以声明JNDI名称,在该名称下您将请求该bean的新实例. 最简单的方法是使用<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要求的Web应用程序部署描述符的元素顺序! 有关详细信息,请参见Servlet规范 .

3. Code Your Application's Use Of This Resource

该资源环境参考的典型用法如下所示:

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. Configure Tomcat's Resource Factory

要配置Tomcat的资源工厂,请在此Web应用程序的<Context>元素中添加一个类似的元素.

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

Note that the resource name (here, bean/MyBeanFactory must match the value specified in the web application deployment descriptor. We are also initializing the value of the bar property, which will cause setBar(23) to be called before the new bean is returned. Because we are not initializing the foo property (although we could have), the bean will contain whatever default value is set up by its constructor.

一些bean具有无法自动从字符串值转换的类型的属性. 使用Tomcat BeanFactory设置此类属性将失败,并显示NamingException. 如果这些bean提供了从字符串值设置属性的方法,则可以将Tomcat BeanFactory配置为使用这些方法. 使用forceString属性完成配置.

假设我们的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具有两个属性,都属于InetAddress类型. 第一个local属性具有一个带有字符串参数的附加setter. 默认情况下,Tomcat BeanFactory将尝试使用参数类型与属性类型相同的自动检测到的setter,然后引发NamingException,因为它不准备将给定的字符串属性值转换为InetAddress . 我们可以告诉Tomcat BeanFactory像这样使用其他设置器:

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

bean属性remote也可以从字符串设置,但是必须使用非标准方法名称host . 要设置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>

可以通过使用逗号作为分隔符的方式在forceString组合多个属性描述. 每个属性描述都仅包含属性名称,在这种情况下,BeanFactory会调用setter方法. 或者它由name=method组成,在这种情况下,可以通过调用method method来设置名为name的属性. 对于String类型或原始类型或其关联的原始包装器类的属性,不需要使用forceString . 将自动检测到正确的设置器,并将应用参数转换.

UserDatabase Resources

0. Introduction

UserDatabase resources are typically configured as global resources for use by a UserDatabase realm. Tomcat includes a UserDatabaseFactory that creates UserDatabase resources backed by an XML file - usually tomcat-users.xml

下面介绍设置全局UserDatabase资源所需的步骤.

1. Create/edit the XML file

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. Declare Your Resource

接下来,修改$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的用户的默认文件权限. 确保这些适当以维护安装的安全性.

如果在领域中引用,则默认情况下,MemoryUserDatabse将监视pathname是否有更改,如果在上次修改时间中发现有更改,则将重新加载文件. 可以通过将watchSource属性设置为false来禁用此功能.

3. Configure the Realm

Realm配置文档中所述,配置UserDatabase Realm以使用此资源.

JavaMail Sessions

0. Introduction

在许多Web应用程序中,发送电子邮件消息是系统功能的必需部分. Java Mail API使此过程相对简单,但是需要客户端应用程序必须了解的许多配置详细信息(包括用于消息发送的SMTP主机的名称).

Tomcat包含一个标准资源工厂,该工厂将为您创建javax.mail.Session会话实例,该实例已经配置为连接到SMTP服务器. 通过这种方式,应用程序完全不受电子邮件服务器配置环境中的更改的干扰-它仅在需要时请求并接收预配置的会话.

下面概述了为此所需的步骤.

1. Declare Your Resource Requirements

您应该做的第一件事是修改Web应用程序部署描述符( /WEB-INF/web.xml ),以声明JNDI名称,在该名称下您将查找预配置的会话. 按照惯例,所有此类名称应解析为mail子上下文(相对于标准java:comp/env命名上下文,该上下文是所有提供的资源工厂的根.典型的web.xml条目可能如下所示:

<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>

警告 -确保您遵守DTD要求的Web应用程序部署描述符的元素顺序! 有关详细信息,请参见Servlet规范 .

2. Code Your Application's Use Of This Resource

A typical use of this resource reference might look like this:

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应用程序部署描述符中声明的资源引用名称相同的名称. 这与在Web应用程序的<Context>元素中配置的资源工厂相匹配,如下所述.

3. Configure Tomcat's Resource Factory

要配置Tomcat的资源工厂,请在此Web应用程序的<Context>元素中添加这样的元素.

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

请注意,资源名称(此处为mail/Session )必须与Web应用程序部署描述符中指定的值匹配. 自定义mail.smtp.host参数的值,使其指向为您的网络提供SMTP服务的服务器.

其他资源属性和值将转换为属性和值,并作为java.util.Properties集合的一部分传递给javax.mail.Session.getInstance(java.util.Properties) . 除了JavaMail规范的附件A中定义的属性外,各个提供程序还可以支持其他属性.

如果资源配置有password属性和mail.smtp.usermail.user属性,则Tomcat的资源工厂将配置javax.mail.Authenticator并将其添加到邮件会话.

4. Install the JavaMail libraries

Download the JavaMail API.

将发行版解压缩并将mail.jar放入$ CATALINA_HOME / lib中,以便在邮件会话资源初始化期间Tomcat可以使用它. 注意:将此jar放在$ CATALINA_HOME / lib和Web应用程序的lib文件夹中都会导致错误,因此请确保仅将其放在$ CATALINA_HOME / lib位置.

5. Restart Tomcat

为了使其他JAR对Tomcat可见,必须重新启动Tomcat实例.

Example Application

Tomcat随附的/examples应用程序包含使用此资源工厂的示例. 可通过" JSP示例"链接进行访问. 实际发送邮件消息的servlet的源代码在/WEB-INF/classes/SendMailServlet.java .

警告 -默认配置假定localhost端口25上有一个SMTP服务器列表. 如果不是这种情况,请编辑此Web应用程序的<Context>元素,并将mail.smtp.host参数的参数值修改为网络上SMTP服务器的主机名.

JDBC Data Sources

0. Introduction

许多Web应用程序需要通过JDBC驱动程序访问数据库,以支持该应用程序所需的功能. Java EE平台规范要求Java EE应用服务器为此目的提供数据源实现(即,用于JDBC连接的连接池). Tomcat提供了完全相同的支持,因此使用此服务在Tomcat上开发的基于数据库的应用程序将在任何Java EE服务器上均保持不变.

有关JDBC的信息,请查阅以下内容:

– Tomcat中的默认数据源支持基于Commons项目中的DBCP 2连接池. 然而,也可以使用实现任何其他连接池javax.sql.DataSource ,通过编写自己的自定义资源工厂,描述如下 .

1. Install Your JDBC Driver

JDBC数据源的使用 JNDI Resource Factory要求您为Tomcat内部类和Web应用程序提供适当的JDBC驱动程序. 通过将驱动程序的JAR文件安装到$CATALINA_HOME/lib目录中,可以最轻松地完成此操作,该驱动程序可用于资源工厂和应用程序.

2. Declare Your Resource Requirements

接下来,修改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>

警告 -确保您遵守DTD要求的Web应用程序部署描述符的元素顺序! 有关详细信息,请参见Servlet规范 .

3. Code Your Application's Use Of This Resource

该资源引用的典型用法如下所示:

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应用程序部署描述符中声明的资源引用名称相同的名称. 这与在Web应用程序的<Context>元素中配置的资源工厂相匹配,如下所述.

4. Configure Tomcat's Resource Factory

要配置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类名称.
  • 用户名 -要传递给我们的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
  • testOnReturn-正确或错误:每次将连接返回到池时是否应使用验证查询来验证连接. 默认值:false

可选的退出线程负责通过删除长时间空闲的任何连接来缩小池. minIdle者不尊重minIdle . 请注意,如果只希望根据配置的maxIdle属性缩小池,则无需激活maxIdle .

逐出器默认情况下处于禁用状态,可以使用以下属性进行配置:

  • timeBetweenEvictionRunsMillis-逐次连续运行之间的毫秒数. 默认值:-1(禁用)
  • numTestsPerEvictionRun-每次运行驱逐程序时,驱逐程序将检查连接是否空闲的连接数. 默认值:3
  • minEvictableIdleTimeMillis-空闲时间(以毫秒为单位),在此时间之后,退出者可以从池中删除连接. 默认值:30 * 60 * 1000(30分钟)
  • testWhileIdle-正确或错误:是否应该在空闲状态下使退出线程使用验证查询来验证连接. 默认值:false

另一个可选功能是删除废弃的连接. 如果应用程序长时间不将其返回到池中,则该连接被称为放弃连接. 池可以自动关闭此类连接并将其从池中删除. 这是应用程序泄漏连接的一种解决方法.

默认情况下,放弃功能是禁用的,可以使用以下属性进行配置:

  • removeAbandonedOnBorrow-正确或错误:借用连接时是否从池中删除废弃的连接. 默认值:false
  • removeAbandonedOnMaintenance-正确或错误:是否在池维护期间从池中删除废弃的连接. 默认值:false
  • removeAbandonedTimeout-假设放弃借用的连接之前经过的秒数. 默认值:300
  • logAbandoned-正确或错误:是否为放弃语句或连接的应用程序代码记录堆栈跟踪. 这增加了严重的开销. 默认值:false

最后,还有各种属性可以进一步调整池行为:

  • defaultAutoCommit-正确或错误:此池创建的连接的默认自动提交状态. 默认值:true
  • defaultReadOnly-正确或错误:此池创建的连接的默认只读状态. 默认值:false
  • defaultTransactionIsolation-设置默认事务隔离级别. 可以是NONEREAD_COMMITTEDREAD_UNCOMMITTEDREPEATABLE_READSERIALIZABLE . 默认值:未设置默认值
  • poolPreparedStatements -true或false:是否合并 PreparedStatements和CallableStatements. 默认值:false
  • maxOpenPreparedStatements-可以同时从语句池分配的最大打开语句数. 默认值:-1(无限制)
  • defaultCatalog-默认目录的名称. 默认值:未设置
  • connectionInitSqls-创建连接后,SQL语句列表将运行一次. 用分号( ; )分隔多个语句. 默认值:无声明
  • connectionProperties-传递给驱动程序以创建连接的特定于驱动程序的属性. 每个属性均以name=value形式给出,多个属性之间用分号( ; )分隔. 默认值:无属性
  • accessToUnderlyingConnectionAllowed-正确或错误:是否允许访问基础连接. 默认值:false

有关更多详细信息,请参阅Commons DBCP 2文档.

Adding Custom Resource Factories

如果没有标准资源工厂可以满足您的需求,则可以编写自己的工厂并将其集成到Tomcat中,然后在Web应用程序的<Context>元素中配置该工厂的使用. 在下面的示例中,我们将创建一个工厂,该工厂仅知道如何从上面的Generic JavaBean Resources示例中创建com.mycompany.MyBean bean.

1. Write A Resource Factory Class

您必须编写一个实现JNDI服务提供者javax.naming.spi.ObjectFactory接口的类. 每当您的Web应用程序在绑定到该工厂的上下文条目上调用lookup()时(假定工厂配置了singleton="false" ),都会调用getObjectInstance()方法,并带有以下参数:

  • Object obj- (可能为null)对象,其中包含可用于创建对象的位置或参考信息. 对于Tomcat,它将始终是类型为javax.naming.Reference的对象,其中包含该工厂类的类名以及用于创建对象的配置属性(来自Web应用程序的<Context> ).被退回.
  • 名称 nameCtx此工厂相对于nameCtx绑定的名称,如果未指定名称,则为null .
  • 上下文nameCtx-相对于其指定name参数的上下文;如果name相对于默认的初始上下文,则为null .
  • 哈希表环境 -用于创建此对象的环境(可能为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. Declare Your Resource Requirements

接下来,修改Web应用程序部署描述符( /WEB-INF/web.xml ),以声明JNDI名称,在该名称下您将请求该bean的新实例. 最简单的方法是使用<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要求的Web应用程序部署描述符的元素顺序! 有关详细信息,请参见Servlet规范 .

3. Code Your Application's Use Of This Resource

该资源环境参考的典型用法如下所示:

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. Configure Tomcat's Resource Factory

要配置Tomcat的资源工厂,请在此Web应用程序的<Context>元素中添加这样的元素.

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

Note that the resource name (here, bean/MyBeanFactory must match the value specified in the web application deployment descriptor. We are also initializing the value of the bar property, which will cause setBar(23) to be called before the new bean is returned. Because we are not initializing the foo property (although we could have), the bean will contain whatever default value is set up by its constructor.

您还将注意到,从应用程序开发人员的角度来看,资源环境引用的声明以及用于请求新实例的编程与用于Generic JavaBean Resources示例的方法相同. 这说明了使用JNDI资源封装功能的优点之一-只要维护兼容的API,就可以更改基础实现,而不必使用这些资源修改应用程序.

by  ICOPY.SITE