JNDI(Java Naming and Directory Interface,Java命名和目录接口)是一个应用程序设计的API,为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口。
1.介绍
Tomcat为每个在其上运行的web应用提供了一个JNDI的** InitialContext**实现实例,它与Java EE应用服务器提供的对应类完全兼容。
Java EE标准在/WEB-INF/web.xml文件中提供了一系列标准元素,用来引用或者定义资源。
2.web.xml配置
可在web应用的部署描述文件(WEB-INF/web.xml)中使用下列元素来定义资源:
-
<evn-entry>
应用的环境项。一个可以用于配置应用运行方式的单值参数。 -
<resource-ref>
资源引用。通常是引用保存某种资源的对象工厂,比如JDBCDataSource
或者JavaMailSession
这样的资源;或者引用配置在Tomcat中的自定义对象工厂中的资源。 -
<resource-evn-ref>
资源环境引用。简化了不需要认证的资源的配置。
通过以上配置,Tomcat就会选择适宜的资源工厂来创建资源,不需要别的信息。Tomcat将会使用/WEB-INF/web.xml中的信息来创建资源。
此外,Tomcat还提供了一些用于JNDI的特殊选项,需要指定在web应用的<Context>元素内,或者位于$CATALINA_BASE/conf/server.xml的<GlobalNamingResources>元素中。
3.context.xml配置
TOmcat特定资源配置位于<Context>元素内,它可以指定在$CATALINA-BASE/conf/server.xml中,或者,最好放在每个web应用的上下文xml文件(META-INF/context.xml)中
要完成Tomcat的特定资源的配置,需要使用<Context>元素中的下列元素:
-
<Environment> - Configure names and values for scalar environment entries that will be exposed to the web application through the JNDI
InitialContext
(equivalent to the inclusion of an<env-entry>
element in the web application deployment descriptor).
对将通过JNDI的InitialContext方法暴露给web应用的环境项的名称与数值加以配置(等同于web应用部署描述文件中包含了一个<evn-entry>元素)。 -
<Resource> - Configure the name and data type of a resource made available to the application (equivalent to the inclusion of a
<resource-ref>
element in the web application deployment descriptor).
定义应用所能用到的资源名称和数据类型(等同于web应用部署描述文件中包含了一个<resource-ref>元素)。 -
<ResourceLink> - Add a link to a resource defined in the global JNDI context. Use resource links to give a web application access to a resource defined in the <GlobalNamingResources> child element of the <Server> element.
添加一个链接,使其指向全局JNDI上下文中定义的资源,使用资源链接可以使web应用访问在<Server>元素中子元素<GlobalNamingResources>中的资源。 -
<Transaction> - Add a resource factory for instantiating the UserTransaction object instance that is available at
java:comp/UserTransaction
.
添加一个资源工厂,用于对java:comp/UserTransaction
获得的UserTransaction接口进行实例化。
一个资源名称既被定义在web应用描述文件的<env-entry>元素中,又被定义在web应用的<Context>元素的<Environment>元素内,那么只有当相应的<Environment>元素被允许(将其中的override属性设置为true),部署描述文件中的值才会优先对待。
4.全局配置
Tomcat为整个服务器维护着一个全局资源的独立命名空间,这些全局资源配置在$CATALINA_BASE/conf/server.xml的<GlobalNamingResources>元素内。可以使用<ResourcesLink>将这些资源暴露给web应用,以便在每一个应用上下文中将其包含进来。
如果已经使用<ResourceLink>定义了资源,那就不必在/WEB-INF/web.xml
文件中定义了。但是建议在/WEB-INF/web.xml
文件中保留相关项,以便记录应用资源请求。
5. 使用资源
在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();
6 标准资源工厂
Tomcat包含一系列资源工厂,为Web应用提供各种服务,通过<Context>元素可以在不修改web应用或者部署描述文件的情况下进行配置。
创建,安装,配置和使用自己的自定义资源工厂类,参看添加自定义资源工厂。
“JDBC DataSource”和“User Transaction”工厂可适用于其他实现了Java EE的其他平台,其他所有的标准资源工厂,以及自行编写的,都是Tomcat专属。
6.1 一般JavaBean资源
6.1.0 简介
该资源工厂能够创建任何符合标准JavaBean命名规范的Java类的对象。如果工厂的singleton属性被设置为false,那么每当对该项进行lookup时,资源工厂会创建出合适的bean类的新实例。
步骤如下:
6.1.1 创建JavaBean类
创建一个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;
}
}
6.1.2 声明资源需求
修改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>
6.1.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());
6.1.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>
6.2 UserDataBase资源
6.2.0 简介
UserDataBase资源通常被配置成通过UserDatabaseRealm所使用的全局资源。Tomcat包含一个UserDatabaseFactory,能够叉棍件基于XML文件(通常是tomcat-users.xml)的UserDatabase资源。
简历全局UserDatabase资源的步骤为:
6.2.1 创建/编辑XML文件
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>
6.2.2 声明资源
修改$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。
6.2.4 配置Realm
配置UserDatabase Realm以便使用该资源。参考Realm配置文档。
6.3 JavaMail会话
6.3.0 简介
Tomcat 多包涵的标准资源工厂可以创建javax.mail.Session会话实例,并且已经配置好连接SMTP服务器上,从而使应用与电子邮件配置环境隔离。无论何时,只需要请求并接受预配置的会话即可。
6.3.1 声明资源需求
修改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规范。
6.3.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应用部署符中声明的完全相同。
6.3.3 配置Tomcat资源工厂
为了配置资源工厂,在<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中。
6.3.4 安装Java Mail库
下载JavaMail API
解压缩后,将mail.jar放到CATALINA_HOME/lib和web应用的/lib文件夹中。
6.3.5 重启Tomcat
为了使用这个额外的jar文件,需要重启Tomcat实例。
6.3.6 范例应用
Tomcat的/examples 应用中有一个使用该资源工厂的范例。可以通过“JSP范例”的链接来访问它。实际发送邮件的servlet源代位于/WEB-INFO/classes/SendMailServlet.java中。
默认配置在localhost的端口25上的SMTP服务器。如果和实际情况不符合,需要编辑web应用的<Context>元素,将mail.smtp.host参数的值修改为你的网络上的SMTP服务器的主机名。
6.4 JDBC数据源
6.4.1 安装JDBC驱动
将驱动的JAR文件安装到CATALINA_HOME/lib
目录中,资源工厂就都能使用这个JDBC驱动了。
6.4.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所需要的元素顺序。
6.3.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应用部署符中的完全相同。
6.3.4 配置Tomcat资源工厂
为了配置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)的配置属性如下:
- driverClassName - Fully qualified Java class name of the JDBC driver to be used.所用JDBC驱动的完全合格的类名
- username - Database username to be passed to our JDBC driver.JDBC驱动所要接受的数据库用户名
- password - Database password to be passed to our JDBC driver.数据库密码
- url - Connection URL to be passed to our JDBC driver. (For backwards compatibility, the property driverName is also recognized.)连接URL(为了考虑向后兼容,同样认可driverName属性,即与之等同)
- initialSize - The initial number of connections that will be created in the pool during pool initialization. Default: 0连接池初始化过程中创建的初始化连接数,默认为0
- maxTotal - The maximum number of connections that can be allocated from this pool at the same time. Default: 8连接池同时能分配的最大连接数,默认为8
- minIdle - The minimum number of connections that will sit idle in this pool at the same time. Default: 0连接池中同时空闲的最小连接数,默认为0
- maxIdle - The maximum number of connections that can sit idle in this pool at the same time. Default: 8连接池中同时空闲的最多连接数,默认为8
- maxWaitMillis - The maximum number of milliseconds that the pool will wait (when there are no available connections) for a connection to be returned before throwing an exception. Default: -1 (infinite)在抛出异常前,连接池等待(没有可用连接)连接返回的最长等待毫秒数,默认为-1(无限长)
额外用来验证连接的属性:
- validationQuery - SQL query that can be used by the pool to validate connections before they are returned to the application. If specified, this query MUST be an SQL SELECT statement that returns at least one row.
- validationQueryTimeout - Timeout in seconds for the validation query to return. Default: -1 (infinite)
- testOnBorrow - true or false: whether a connection should be validated using the validation query each time it is borrowed from the pool. Default: true
- testOnReturn - true or false: whether a connection should be validated using the validation query each time it is returned to the pool. Default: false
可选的evictor thread会清楚空闲时间较长的连接,从而缩小连接池。evictor thread不受minIndle属性值的空闲。
如果只想通过配置的minIdle属性来缩小连接池,那么不需要使用evictor thread
默认evictor是禁用的,可以通过下列属性来配置它:
- timeBetweenEvictionRunsMillis - The number of milliseconds between consecutive runs of the evictor. Default: -1 (disabled)
- numTestsPerEvictionRun - The number of connections that will be checked for idleness by the evictor during each run of the evictor. Default: 3
- minEvictableIdleTimeMillis - The idle time in milliseconds after which a connection can be removed from the pool by the evictor. Default: 30601000 (30 minutes)
- testWhileIdle - true or false: whether a connection should be * validated by the evictor thread using the validation query while sitting idle in the pool. Default: false
可选的配置废弃连接的移除。如果应用很久不把某个连接返回连接池,那么该连接被称为废弃连接,连接池会自动关闭这样的连接,将其从连接池中移除。
默认禁止废弃连接,通过下列属性来配置:
- removeAbandoned - true or false: whether to remove abandoned connections from the pool. Default: false
- removeAbandonedTimeout - The number of seconds after which a borrowed connection is assumed to be abandoned. Default: 300
- logAbandoned - true or false: whether to log stack traces for application code which abandoned a statement or connection. This adds serious overhead. Default: false
连接池行为的属性微调:
- defaultAutoCommit - true or false: default auto-commit state of the connections created by this pool. Default: true
- defaultReadOnly - true or false: default read-only state of the connections created by this pool. Default: false
- defaultTransactionIsolation - This sets the default transaction isolation level. Can be one of NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE. Default: no default set
- poolPreparedStatements - true or false: whether to pool PreparedStatements and CallableStatements. Default: false
- maxOpenPreparedStatements - The maximum number of open statements that can be allocated from the statement pool at * the same time. Default: -1 (unlimited)
- defaultCatalog - The name of the default catalog. Default: not set
- connectionInitSqls - A list of SQL statements run once after a Connection is created. Separate multiple statements by semicolons (;). Default: no statement
- connectionProperties - A list of driver specific properties passed to the driver for creating connections. Each property is given as name=value, multiple properties are separated by semicolons (;). Default: no properties
- accessToUnderlyingConnectionAllowed - true or false: whether accessing the underlying connections is allowed. Default: false
6.4 自定义资源工厂
如果标准工厂无法满足需求,可以自行编写资源工厂,然后集成到Tomcat中。
6.4.1 编写资源工厂类
需要编写一个类来实现JNDI服务提供者javax.naming.spi.ObjectFactory接口。web应用绑定到该工厂(假设工厂配置中singleton="false")的上下文项上调用lookup()时,就会调用getObjectInstance()方法,该方法参数如下:
-
Object obj - The (possibly null) object containing location or reference information that can be used in creating an object. For Tomcat, this will always be an object of type
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. -
Name name - The name to which this factory is bound relative to
nameCtx
, ornull
if no name is specified. -
Context nameCtx - The context relative to which the
name
parameter is specified, ornull
ifname
is relative to the default initial context. - Hashtable environment - The (possibly null) environment that is used in creating this object. This is generally ignored in Tomcat object factories.
创建一个能够生成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应用看到了。
6.4.2 声明资源需求
修改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>
6.4.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());
6.4.4 配置Tomcat资源工厂
为了配置Tomcat资源工厂,在<Context>中添加以下元素:
<Context ...>
...
<Resource name="bean/MyBeanFactory" auth="Container"
type="com.mycompany.MyBean"
factory="com.mycompany.MyBeanFactory"
singleton="false"
bar="23"/>
...
</Context>
网友评论