NDI,Java Naming Directory Interface,J2EE的标准之一,所有的J2EE容器都必须提供一个JNDI的服务,大多数人会把数据源配置在Tomcat的JNDI服务中。JNDI 的主要功能可以这样描述,它使用一张哈希表存储对象(大多数的J2EE容器也的确是这样做的),然后,开发人员可以使用键值,也就是一个字符串来获取这个对象。这里就包括取JNDI的两个最主要操作,bind和lookup。bind操作负责往哈希表里存对象,存对象的时候要定义好对象的键值字符 串,lookup则根据这个键值字符串往外取对象。
JNDI的命称可能会让人产生混淆,似乎觉得这是一个用来操作目录的,事实上,我更愿意把这个目录理解成为JNDI存放对象时使用的格式,也就是说,JNDI以目录的方式存储对象的属性。例如,用户通过JNDI存储一个汽车对象,那么,汽车就是根目录,汽车的轮子、引擎之类的子对象就算是子目录,而属性,比如说汽车的牌子、重量之类,就算是汽车目录下的文件。
JNDI的功能既然就是根据一个字符串键值就可以取得一个想要得到的对象,我一开始就觉得这不是跟COM或CORB一样吗?SUN也是有野心的企业啊,JNDI应该就是它要努力推行的JAVA下的分布式开发的标准吧。
JNDI 的出现应该就是为了分步式开发服务的,有人负责开发这种分布式对象,有人只需要使用这些分布式对象就可以了,这两组人不必属于同一个公司,而且这种开发通 常应该是不并行的,也不必是会了同一个项目服务。就如果数据源对象,它放在JNDI中,只要想要用的人,直接通过JNDI服务取来用就可以了,至于当初是谁把它放进JNDI中的,还是不用操这份心了吧。而我一直没有使用JNDI,也就是这个原因,项目中的所有对象都在我控制之下,我不去使用别人的对象,也 没打算把我的对象贡献出来给别人使用,那自然也就没必要去跟JNDI打交道。我觉得是否使用JNDI,这应该是关键原因,至于什么方便性、安全性之类的考虑,应该不是JNDI的主要目的,就如同你可以用JAVA来做网站,但JAVA并不是专门用来做网站的。
可能有人觉得这种功能跟IoC也很象,这个我倒不觉得,虽然对于对象的使用人员来说的确是这种感觉,且不说IoC需要为对象定义接口,而JNDI并无此限制,先说这里有一个使用环境问 题,我觉得IoC是用来解决并行开发问题的,也就是说IoC主要是用于明确设计人员与实现/使用人员的分工,无论是设计的,还是使用的,通常是一个项目组 里的人,使用IoC,可以使得设计人员专注于设计,加快设计速度。因此,IoC的用途要比JNDI广泛的多,现在大型系统中,不使用IoC的已经很少了。
在J2EE环境下使用JNDI是非常简单的事,因为所有的J2EE容器都要实现JNDI服务,所以,在J2EE环境下使用JNDI,与使用 Hashtable也没有什么太大区别。只有一点限制,那就是绑定对象时,对象所属的类必须实现java.io.Serializable接口,这一点也实在一点也不困难,几乎所有用到的Java类都实现了这个接口,对于自定义的类,在接口实现列表里把这个接口加进去也就是了。
下面,我将演示一下如何在J2EE环境下使用JNDI,为了保证代码的通用性,我不使用struts之类的框架,而是直接使用标准JSP和Servlet实现。我将该项目的名称定为jndi_test
要使用JNDI,需要先到SUN的网站上去下载jndi.jar。
本项目包括5个JSP,功能说明如下:
bind_result.jsp:绑定对象后的返回页面
lookup_result.jsp:用于显示检索对象
本节中用到的JSP代码如下,代码都简单地很,就不多做解释了。
bind_result.jsp和内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" session="false"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<
html
>
<
head
>
<
meta
http-equiv
=
"Content-Type"
content
=
"text/html; charset=UTF-8"
>
<
title
> JNDI Test - Bind result </
title
>
</
head
>
<
body
>
数据已经绑定成功!
</
body
>
</
html
>
|
lookup_result.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" session="false"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<
html
>
<
head
>
<
meta
http-equiv
=
"Content-Type"
content
=
"text/html; charset=UTF-8"
>
<
title
> JNDI Test - Lookup result </
title
>
</
head
>
<
body
>
<%
Object o = request.getAttribute("found_jndi_obj");
out.println(o);
%>
</
body
>
</
html
>
|
本例包括两个Servlet,功能说明如下:
BindServlet:用于在JNDI服务中绑定一个对象
LookupServlet:用于在JNDI服务中取出一个对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
import
java.io.IOException;
import
java.util.Date;
import
javax.naming.Context;
import
javax.naming.InitialContext;
import
javax.servlet.RequestDispatcher;
import
javax.servlet.ServletContext;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
public
class
BindServlet
extends
HttpServlet
{
private
static
final
long
serialVersionUID = 5219969790998794367L;
@Override
protected
void
doGet(HttpServletRequest req, HttpServletResponse resp)
throws
ServletException, IOException
{
this
.doPost(req, resp);
}
@Override
protected
void
doPost(HttpServletRequest req, HttpServletResponse resp)
throws
ServletException, IOException
{
try
{
Context jndi_ctx =
new
InitialContext();
String key =
"jndi_object"
;
jndi_ctx.rebind(key,
new
Date());
}
catch
(Exception ex)
{
ex.printStackTrace();
}
ServletContext context =
this
.getServletContext();
RequestDispatcher dispatcher = context.getRequestDispatcher(
"/jndi/bind_result.jsp"
);
dispatcher.forward(req, resp);
}
}
|
注意:使用rebind而不是bind绑定对象是因为,使用bind时,如果已经有对象绑定到该键值上,则会抛出异常。因为只是示例代码,所以我只是绑定了一个最简单的日期对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
import
java.io.IOException;
import
javax.naming.Context;
import
javax.naming.InitialContext;
import
javax.servlet.RequestDispatcher;
import
javax.servlet.ServletContext;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
public
class
LookupServlet
extends
HttpServlet
{
private
static
final
long
serialVersionUID = 6677219828267184673L;
@Override
protected
void
doGet(HttpServletRequest req, HttpServletResponse resp)
throws
ServletException, IOException
{
this
.doPost(req, resp);
}
@Override
protected
void
doPost(HttpServletRequest req, HttpServletResponse resp)
throws
ServletException, IOException
{
try
{
Context jndi_ctx =
new
InitialContext();
String key =
"jndi_object"
;
Object o = jndi_ctx.lookup(key);
req.setAttribute(
"found_jndi_obj"
, o);
}
catch
(Exception ex)
{
ex.printStackTrace();
}
ServletContext context =
this
.getServletContext();
RequestDispatcher dispatcher = context.getRequestDispatcher(
"/jndi/lookup_result.jsp"
);
dispatcher.forward(req, resp);
}
}
|
在web.xml中,加入了servlet映射:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<
servlet
>
<
servlet-name
>BindServlet </
servlet-name
>
<
servlet-class
>jndi.BindServlet </
servlet-class
>
</
servlet
>
<
servlet-mapping
>
<
servlet-name
>BindServlet </
servlet-name
>
<
url-pattern
>/bind</
url-pattern
>
</
servlet-mapping
>
<
servlet
>
<
servlet-name
>LookupServlet </
servlet-name
>
<
servlet-class
>jndi.LookupServlet </
servlet-class
>
</
servlet
>
<
servlet-mapping
>
<
servlet-name
>LookupServlet </
servlet-name
>
<
url-pattern
>/lookup</
url-pattern
>
</
servlet-mapping
>
|