我们分两个部分来研究JNDI,首先了解一些JNDI的框架,然后再写一个类似helloword实例并分析源码
一: JNDI架构及接口:
(1):架构图
JNDI主要分三个部分,其中JNDi API提供给应用端查找调用服务接口,JNDI SPI提供给供应商实现。
(2):JNDI程序包
1、Javax.naming:包含了访问命名服务的类和接口。例如,它定义了Context接口,这是命名服务执行查询的入口。
2、Javax.naming.directory:对命名包的扩充,提供了访问目录服务的类和接口。例如,它为属性增加了新的类,提供了表示目录上下文的DirContext接口,定义了检查和更新目录对象的属性的方法。
3、Javax.naming.event:提供了对访问命名和目录服务时的事件通知的支持。例如,定义了NamingEvent类,这个类用来表示命名/目录服务产生的事件,定义了侦听NamingEvents的NamingListener接口。
4、Javax.naming.ldap:这个包提供了对LDAP 版本3扩充的操作和控制的支持,通用包javax.naming.directory没有包含这些操作和控制。
5、Javax.naming.spi:这个包提供了一个方法,通过javax.naming和有关包动态增加对访问命名和目录服务的支持。这个包是为有兴趣创建服务提供者的开发者提供的。
二:JNDI的使用示例
(1)服务提供商实现JNDI SPI提供服务
spi接口:InitialContextFactory
1:实现Context
public class AnimalContext extends InitialContext{
private static HashMap<String, Object> map = new HashMap<String, Object>();
public AnimalContext() throws NamingException {
super();
}
public void unbind(String name) throws NamingException {
map.remove(name);
}
public void bind(String name, Object o) throws NamingException{
map.put(name, o);
}
public Object lookup(String name) throws NamingException{
return map.get(name);
}
}
2:实现contextFactory
public class AnimalContextFactory implements InitialContextFactory{
/**
* environment是应用端提供的包括服务厂商所需要的参数
*/
@Override
public Context getInitialContext(Hashtable<?, ?> environment)
throws NamingException {
// TODO Auto-generated method stub
AnimalContext context = new AnimalContext();
context.bind("cat", new Cat("redCat"));
context.bind("dog", new Dog("yellowDog"));
context.bind("crow", new Craw("milkCraw"));
return new AnimalContext();
}
}
3: 对象接口
/**
* 动物
*/
public interface Animal {
public String eat(String food);
}
/**
* 猫
*/
public class Cat implements Animal{private String name;
public Cat(String name){
this.name = name;
}public String eat(String food) {
return this.name + ” eat ” + food;
}public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}
}
/**
* 牛
*/
public class Craw implements Animal{private String name;
public Craw(String name){
this.name = name;
}public String eat(String food) {
return this.name + ” eat ” + food;
}public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}
}
/**
* 狗
*/
public class Dog implements Animal{private String name;
public Dog(String name){
this.name = name;
}public String eat(String food) {
return this.name + ” craw ” + food;
}public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}
}
(2)应用端通过JNDI API调用服务
public class CosumeClient{
public static void main(String[] args) {
try {
Hashtable<String, Object> env = new Hashtable<String, Object>();
env.put("java.naming.factory.initial", "jndi.context.AnimalContextFactory");
Context clientContext = new InitialContext(env);
System.out.println(((Animal)clientContext.lookup("cat")).eat("fish"));
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
执行结果:redCat eat fish。
通过这个示例就对JNDI有一些了解了。
那么下面我们来研究一下JNDI源码
(3)JNDI源码分析
客户端调用执行:
Context clientContext = new InitialContext(env);
时后面运行的代码是 NamingManager 的getInitialContext(Hashtable<
?,?> env) 方法里面的这段代码
public static Context getInitialContext(Hashtable<?,?> env)
throws NamingException {
InitialContextFactory factory;
InitialContextFactoryBuilder builder = getInitialContextFactoryBuilder();
if (builder == null) {
// No factory installed, use property
// Get initial context factory class name
String className = env != null ?
(String)env.get(Context.INITIAL_CONTEXT_FACTORY) : null;
if (className == null) {
NoInitialContextException ne = new NoInitialContextException(
"Need to specify class name in environment or system " +
"property, or as an applet parameter, or in an " +
"application resource file: " +
Context.INITIAL_CONTEXT_FACTORY);
throw ne;
}
try {
factory = (InitialContextFactory)
helper.loadClass(className).newInstance();
} catch(Exception e) {
NoInitialContextException ne =
new NoInitialContextException(
"Cannot instantiate class: " + className);
ne.setRootCause(e);
throw ne;
}
} else {
factory = builder.createInitialContextFactory(env);
}
return factory.getInitialContext(env);
}
将应用端传递的jndi.context.AnimalContextFactory通过反射加载进来并创建initialContext。