Tomcat为每个在其上运行的web应用提供了一个JNDI的** InitialContext**实现实例,它与Java EE应用服务器提供的对应类完全兼容。 Java EE标准在/WEB-INF/web.xml文件中提供了一系列标准元素,用来引用或者定义资源。
可在web应用的部署描述文件(WEB-INF/web.xml)中使用下列元素来定义资源:
<evn-entry>应用的环境项。一个可以用于配置应用运行方式的单值参数。<resource-ref>资源引用。通常是引用保存某种资源的对象工厂,比如JDBC DataSource或者JavaMail Session这样的资源;或者引用配置在Tomcat中的自定义对象工厂中的资源。<resource-evn-ref>资源环境引用。简化了不需要认证的资源的配置。通过以上配置,Tomcat就会选择适宜的资源工厂来创建资源,不需要别的信息。Tomcat将会使用/WEB-INF/web.xml中的信息来创建资源。
此外,Tomcat还提供了一些用于JNDI的特殊选项,需要指定在web应用的<Context>元素内,或者位于$CATALINA_BASE/conf/server.xml的<GlobalNamingResources>元素中。
TOmcat特定资源配置位于<Context>元素内,它可以指定在$CATALINA-BASE/conf/server.xml中,或者,最好放在每个web应用的上下文xml文件(META-INF/context.xml)中 要完成Tomcat的特定资源的配置,需要使用<Context>元素中的下列元素:
InitialContext (equivalent to the inclusion of an <env-entry> element in the web application deployment descriptor).
对将通过JNDI的InitialContext方法暴露给web应用的环境项的名称与数值加以配置(等同于web应用部署描述文件中包含了一个<evn-entry>元素)。<resource-ref> element in the web application deployment descriptor).
定义应用所能用到的资源名称和数据类型(等同于web应用部署描述文件中包含了一个<resource-ref>元素)。java:comp/UserTransaction.
添加一个资源工厂,用于对java:comp/UserTransaction获得的UserTransaction接口进行实例化。一个资源名称既被定义在web应用描述文件的<env-entry>元素中,又被定义在web应用的<Context>元素的<Environment>元素内,那么只有当相应的<Environment>元素被允许(将其中的override属性设置为true),部署描述文件中的值才会优先对待。
Tomcat为整个服务器维护着一个全局资源的独立命名空间,这些全局资源配置在$CATALINA_BASE/conf/server.xml的<GlobalNamingResources>元素内。可以使用<ResourcesLink>将这些资源暴露给web应用,以便在每一个应用上下文中将其包含进来。
如果已经使用<ResourceLink>定义了资源,那就不必在/WEB-INF/web.xml文件中定义了。但是建议在/WEB-INF/web.xml文件中保留相关项,以便记录应用资源请求。
在web应用最初部署时候,就配置InitialContext,使其可以被web应用的各组件所访问(只读访问)。
JNDI命名空间的java:comp/env部分中包含着所有的配置项与资源。所以访问资源例子(JDBC数据源)如下:
// 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包含一系列资源工厂,为Web应用提供各种服务,通过<Context>元素可以在不修改web应用或者部署描述文件的情况下进行配置。 创建,安装,配置和使用自己的自定义资源工厂类,参看添加自定义资源工厂。 “JDBC DataSource”和“User Transaction”工厂可适用于其他实现了Java EE的其他平台,其他所有的标准资源工厂,以及自行编写的,都是Tomcat专属。
该资源工厂能够创建任何符合标准JavaBean命名规范的Java类的对象。如果工厂的singleton属性被设置为false,那么每当对该项进行lookup时,资源工厂会创建出合适的bean类的新实例。 步骤如下:
创建一个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应用部署描述文件(WEB-INF/web.xml)声明JNDI名称,并据此请求该Bean类的新实例。
<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>资源引用的典型用例如下:
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资源工厂,为Web应用的<Context>元素添加下列元素:
<Context ...>
...
<Resource name="bean/MyBeanFactory" auth="Container"
type="com.mycompany.MyBean"
factory="org.apache.naming.factory.BeanFactory"
bar="23"/>
...
</Context>UserDataBase资源通常被配置成通过UserDatabaseRealm所使用的全局资源。Tomcat包含一个UserDatabaseFactory,能够叉棍件基于XML文件(通常是tomcat-users.xml)的UserDatabase资源。 简历全局UserDatabase资源的步骤为:
XML文件通常位于$CATALINA_BASE/conf/tomcat-users.xml,但是也可以放在文件系统的任何位置。
典型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>修改$CATALINA_BASE/conf/server.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可以采用绝对路径或者相对路径,相对路径是相对于$CATALINA_BASE。
属性readonly可选,默认为true。
配置UserDatabase Realm以便使用该资源。参考Realm配置文档。
Tomcat 多包涵的标准资源工厂可以创建javax.mail.Session会话实例,并且已经配置好连接SMTP服务器上,从而使应用与电子邮件配置环境隔离。无论何时,只需要请求并接受预配置的会话即可。
修改web应用的部署描述文件(/WEB-INF/web.xml)声明JNDI名称以便借此查找预配置会话。按照惯例,所有这样的名字都应该解析道mai子上下文。 典型的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>注意:要遵循web应用部署文件中DTD所需要的元素顺序。参考Servlet规范。
典型的资源引用用例:
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>元素中添加以下元素:
<Context ...>
...
<Resource name="mail/Session" auth="Container"
type="javax.mail.Session"
mail.smtp.host="localhost"/>
...
</Context>注意,资源名(这里是mail/Session)必须与web应用部署描述文件中的值相匹配。对于mail.smtp.host参数,可以用为你提供SMTP服务的服务器来自定义。 额外的资源属性与值将会被转换成相关的属性和值被传入javax.mail.Session.getInstance(java.util.Properties),作为参数集java.util.Properties中的一部分。 如果资源配置中包含password属性,以及mail.smtp.user或者mail.user属性,那么Tomcat资源工厂将配置添加javax.mail.Authenticator到邮件Session中。
下载JavaMail API 解压缩后,将mail.jar放到
CATALINA_HOME/lib和web应用的/lib文件夹中。
为了使用这个额外的jar文件,需要重启Tomcat实例。
Tomcat的/examples 应用中有一个使用该资源工厂的范例。可以通过“JSP范例”的链接来访问它。实际发送邮件的servlet源代位于/WEB-INFO/classes/SendMailServlet.java中。
默认配置在localhost的端口25上的SMTP服务器。如果和实际情况不符合,需要编辑web应用的<Context>元素,将mail.smtp.host参数的值修改为你的网络上的SMTP服务器的主机名。
将驱动的JAR文件安装到CATALINA_HOME/lib目录中,资源工厂就都能使用这个JDBC驱动了。
修改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所需要的元素顺序。
资源的典型引用用例:
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应用部署符中的完全相同。
为了配置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>Tomcat标准资源工厂(org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory)的配置属性如下:
额外用来验证连接的属性:
可选的evictor thread会清楚空闲时间较长的连接,从而缩小连接池。evictor thread不受minIndle属性值的空闲。 如果只想通过配置的minIdle属性来缩小连接池,那么不需要使用evictor thread 默认evictor是禁用的,可以通过下列属性来配置它:
可选的配置废弃连接的移除。如果应用很久不把某个连接返回连接池,那么该连接被称为废弃连接,连接池会自动关闭这样的连接,将其从连接池中移除。 默认禁止废弃连接,通过下列属性来配置:
连接池行为的属性微调:
如果标准工厂无法满足需求,可以自行编写资源工厂,然后集成到Tomcat中。
需要编写一个类来实现JNDI服务提供者javax.naming.spi.ObjectFactory接口。web应用绑定到该工厂(假设工厂配置中singleton="false")的上下文项上调用lookup()时,就会调用getObjectInstance()方法,该方法参数如下:
javax.naming.Reference, which contains the class name of this factory class, as well as the configuration properties (from the <Context> for the web application) to use in creating objects to be returned.nameCtx, or null if no name is specified.name parameter is specified, or null if name is relative to the default initial context.创建一个能够生成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);
}
}首先参照
CATALINA_HOME/lib,或者$CATALINA_HOME/lib中的一个JAR文件中,这样,所需的类文件就能被Catalina内部资源和web应用看到了。
修改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>资源引用的典型用例:
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资源工厂,在<Context>中添加以下元素:
<Context ...>
...
<Resource name="bean/MyBeanFactory" auth="Container"
type="com.mycompany.MyBean"
factory="com.mycompany.MyBeanFactory"
singleton="false"
bar="23"/>
...
</Context>