本文主要探讨jetty中的JNDI实现。
JNDI的入口类是javax.naming.InitialContext,其中的getURLOrDefaultInitCtx方法用于查找特定提供商的初始上下文对象,代码:
protected Context getURLOrDefaultInitCtx(String name)
throws NamingException {
if (NamingManager.hasInitialContextFactoryBuilder()) {
return getDefaultInitCtx();
}
String scheme = getURLScheme(name);
if (scheme != null) {
Context ctx = NamingManager.getURLContext(scheme, myProps);
if (ctx != null) {
return ctx;
}
}
return getDefaultInitCtx();
}
如果name字符串是一个URL,则使用NamingManager.getURLContext方法获得指定的上下文,否则使用默认上下文。例如 java:comp/env就是一个URL形式的name,jdbc/mysql1就不是URL形式,必定会通过默认上下文查找。
如何确定上下文工厂?
InitialContext的javadoc中已经描述的很清除了
1. 构造方法的环境参数、(适当属性的)applet 参数,以及系统属性中最先出现的属性。
2. 应用程序资源文件 (jndi.properties)。
Jetty中是通过jndi.properties资源文件来配置JNDI上下文工厂的,文件存放在jetty-jndi-7.4.0.v20110414.jar中,文件内容是:
java.naming.factory.url.pkgs=org.eclipse.jetty.jndi
java.naming.factory.initial=org.eclipse.jetty.jndi.InitialContextFactory
对于java:comp开头的name,使用org.eclipse.jetty.jndi.java.javaURLContextFactory来初始化上下文,对于其他类型的name,使用org.eclipse.jetty.jndi.InitialContextFactory。这两种初始化方法有不同的上下文根节点,是两颗上下文树。
默认根上下文存储在org.eclipse.jetty.jndi.local.localContextRoot类中,是一个静态变量。
java:开头的根上下文存储在org.eclipse.jetty.jndi.java.javaRootURLContext类中,是一个静态变量。
如何做到每个应用有私有的java:comp/env命名空间?
static{
try{
__javaNameParser = new javaNameParser();
__nameRoot = new NamingContext();
__nameRoot.setNameParser(__javaNameParser);
StringRefAddr parserAddr = new StringRefAddr("parser", __javaNameParser.getClass().getName());
Reference ref = new Reference ("javax.naming.Context",
parserAddr,
ContextFactory.class.getName(),
(String)null);
//bind special object factory at comp
__nameRoot.bind ("comp", ref);
}
catch (Exception e){
__log.warn(e);
}
}
jetty在__nameRoot中绑定了一个名为comp的Reference类型的变量,这是一个引用。这个变量的工厂类是:org.eclipse.jetty.jndi.ContextFactory,这个类中基于classloader来创建上下文对象。因此在应用程序内部,使用InitialContext的lookup方法查找类似java:comp/env名称的对象时,将基于调用环境返回应用程序相关的上下文,也就是应用程序私有的上下文。
从localContextRoot类的名字也可以看出,jetty中的JNDI实现是本机JNDI实现,不支持跨JVM的远程对象查找。
IBM的websphere和Oracle的weblogic等服务器都支持远程对象查找,资源对象可以存放在一个JVM中,并在多个其他的JVM中使用这个资源。开源的JBoss服务器也支持远程对象查找。
我感觉远程JNDI的用处不多,主要查找的都是一些轻量级的服务对象,如:JMSContextProvider。