如果任何标准资源工厂都不能满足你的要求,你可以编写你自己的资源工厂,并把它整合到Tomcat 5里面,再在conf/server.xml configuration文件里配置怎样使用它。在下面的例子里,你将要产生一个资源工厂,这个工厂仅仅知道怎样产生上面所描述的Generic JavaBean Resources例子里的com.mycompany.MyBean beans 。
编写一个资源工厂类
你必须编写一个实施JNDI服务供给者
javax.naming.spi.ObjectFactory 界面的类。每次你的程序在这个工厂绑定的context entry上调用lookup() ,这个getObjectInstance()方法就会被叫到,有以下这些参数: lookup()
- Object obj - 包含可用于制造一个对象(object)的地址或索引信息的对象(很可能是空值)??????对Tomcat来说,这总是一个
javax.naming.Reference类型的对象,它包括这个工厂类的类名,以及用来产生返回对象的配置属性(来自conf/server.xml)。
- Name name - 这个工厂绑定的与
nameCtx有关联的名字,如果没有名字被指定,它就是空值。
- Context nameCtx -
名称参数相对于这个context被指定,如果名称是相对于默认的初始context,它就是空值。
- 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 name, 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>元素所包含的参数基础上populating它的属性,而这个<ResourceParams>元素是配置这个工厂用的(参见下面)。你应该注意,必须跳过所有名字叫工厂的参数——这个参数是用来指定工厂类自身的名字(在这里的情况下是com.mycompany.MyBeanFactory),而不是用来指定要被配置的bean的属性。 com.mycompany.MyBeanFactory
关于ObjectFactory的更多信息,请参看JNDI 1.2 Service
Provider Interface (SPI) Specification 。 JNDI 1.2 Service
Provider Interface (SPI) Specification
你需要对照一个包括所有$CATALINA_HOME/common/lib 和$CATALINA_HOME/server/lib目录里的JAR文件的class path来编译这个类。当你完成以后,把这个工厂类(以及相关的bean类)以未包装形式放在$CATALINA_HOME/common/classes下面,或者放在$CATALINA_HOME/common/lib里的一个JAR文件里。通过这种方式,所需要的类文件既可以被Catalina内部资源又可以被你的网络程序使用。
声明你的资源要求
下一步,修改你的网络程序部署描述符( /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所要求的。详细信息请参看Servlet 规范 。
编写使用这个资源的程序
典型的使用这个资源环境索引的编码看起来象这样:
 |  |  |
 | 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的资源工厂
要配置Tomcat的资源工厂,把这样一个元素加入到$CATALINA_HOME/conf/server.xml 文件里边,再把它嵌套在这个网络程序的Context元素里(或者嵌套在一个DefaultContext元素for the surrounding
<Host> or <Engine> element.?????) DefaultContext
<Host>
 |  |  |
 | <Context ...>
...
<Resource name="bean/MyBeanFactory" auth="Container"
type="com.mycompany.MyBean"/>
<ResourceParams name="bean/MyBeanFactory">
<parameter>
<name>factory</name>
<value>com.mycompany.MyBeanFactory</value>
</parameter>
<parameter>
<name>bar</name>
<value>23</value>
</parameter>
</ResourceParams>
...
</Context> |  |
 |  |  |
注意资源名称(这里是bean/MyBeanFactory)必须与网络程序部署描述符里指定的值相对映。我们也还要初始化bar property的值,这会在返回新的bean之前引起调用setBar(23)。因为我们没有初始化foo property(尽管我们也可以这样做),bean会包含它的构造器设置的任何默认值。 foo
你会注意到,从程序开发员的角度来看,对资源环境索引的声明,和用于请求新实例的编程,与Generic JavaBean Resources例子里使用的方法完全一样。这里举例说明了使用JNDI资源来封装功能(functionality)的一个优点——那就是,只要你保持相兼容的APIs,你可以改变下面的实施(underlying implementation)而不需要使用资源来修改程序。