一、JNDI在Java EE中的应用 JNDI
技术是Java EE规范中的一个重要“幕后”角色,它为Java EE容器、组件提供者和应用程序之间提供了桥梁作用:Java
EE容器同时扮演JNDI提供者角色,组件提供者将某个服务的具体实现部署到容器上,应用程序通过标准的JNDI接口就可以从容器上发现并使用服务,而不
用关心服务的具体实现是什么,它的具体位置在哪里。
下面以一个常见的J2EE应用
场景来看四种角色(组件接口、容器、组件提供者、应用程序)是如何围绕JNDI来发挥作用的: 组件接口 数据源DataSource是一种很常见的服务。我们通常将组件接口绑定到容器的Context上供客户调用。
Java EE容器 Tomcat是一种常见的Java
EE容器,其他的还有JBoss,WebLogic,它们同时也实现了JNDI提供者规范。容器通常提供一个JNDI注入场所供加入组件的具体实现,比如
Tomcat中的Server.xml配置文件。
组件提供者 众
多数据库厂商提供了DataSource的实现,比如OracleDataSource,MySQLDataSource,XXXDataSource
等。我们将该实现的部署到容器中:将一系列jar加入classpath中,在Server.xml中配置DataSource实现,如: <Resource
name="jdbc/MyDB" auth="Container" type="javax.sql.DataSource" ..../>
应用程序 一个JSP/Servlet应用程序。通过JNDI接口使用
DataSource服务,如: Context initContext = new InitialContext(); Context
envContext = (Context)initContext.lookup("java:/comp/env"); DataSource
ds = (DataSource)envContext.lookup("jdbc/MyDB");
关于在Tomcat中如何配置DataSource,可以参考文档:http://tomcat./tomcat-5.5-doc/jndi-datasource-examples-howto.html。 关于在Tomcat中如何配置其他JNDI服务,可以参考文档:http://tomcat./tomcat-5.5-doc/jndi-resources-howto.html。
二、
JNDI实例演练:在Java SE中使用JNDI 要在Java
EE中环境中提供一个独立的实例不太容易。下面以一个独立的Java
SE应用来演练JNDI的使用过程。在该应用中,我们使用JNDI来使用两种假想的服务:数据库服务DBService和日志服务LogService。
1、指定JNDI提供者 要使用JNDI,首先要配置JNDI提供者。在我们的
Java SE应用中,没有Java
EE容器充当JNDI提供者,因此我们要指定其他的JNDI提供者。在我们的例子里,我们使用SUN的文件系统服务提供者File System
Service Provider。由于SUN的文件系统服务提供者并没有包含在JDK中,我们需要从SUN网站上下载:http://java./products/jndi/downloads/index.html。它包含两个jar文件:fscontext.jar和providerutil.jar。我们将这两个文件加入项目的类
路径中。
2、定义服务接口 首先,我们
在服务接口package(xyz.service)中定义服务接口:DBService和LogService,分别表示数据库服务和日志服务。
♦
数据库服务接口 DBService.java
package xyz.service;
public interface DBService { String
getLocation(); //获取数据库位置
String getState(); //获取数据库状态 void
accessDB(); //访问数据库 void setProperty(int index,String
property); //设置数据库信息 }
♦日志服务接口 LogService.java
package xyz.service;
public interface LogService { void
log(String message); //记录日志 }
3、组件提供者实现服务接口 接
下来,我们在组件提供者package(xyz.serviceprovider)中提供DBService和LogService的实
现:SimpleDBService和SimpleLogService。为了让服务能够在JNDI环境中使用,根据JNDI规范,我们同时定义两个对象
工厂类SimpleDBServiceFactory和SimpleLogServiceFactory,分别用来创建服务实例。
♦
数据库服务接口实现 SimpleDBService.java
package xyz.serviceprovider;
import
javax.naming.NamingException; import javax.naming.Reference; import
javax.naming.Referenceable; import javax.naming.StringRefAddr;
import xyz.service.DBService;
//为了将数据库服务实例加入JNDI的Context中,我们需要实
现Referenceable接口,并实现RetReference方法。 //关于Reference和Referenceable,请参考上一
篇:Java技术回顾之JNDI:JNDI API public class SimpleDBService implements
Referenceable, DBService { private String
location="mydb//local:8421/defaultdb";//数据库服务属性之一:数据库位置 private
String state="start"; //数据库服务属性之二:数据库状态
public Reference getReference()
throws NamingException { //Reference是对象的引用,Context中存放的是Reference,为了
从Reference中还原出对象实例, //我们需要添加RefAddr,它们是创建对象实例的线索。在我们的
SimpleDBService中,location和state是这样两个线索。 Reference ref=new
Reference(getClass().getName(),SimpleDBServiceFactory.class.getName(),null); ref.add(new
StringRefAddr("location",location)); ref.add(new
StringRefAddr("state",state)); return ref; }
public void accessDB() { if(state.equals("start")) System.out.println("we
are accessing DB."); else System.out.println("DB is not
start."); }
public String getLocation() { return
location; }
public String getState() { return state; }
public void setProperty(int
index,String property){ if(index==0) location=property; else state=property; } }
♦数据库服务对象工厂类 SimpleDBServiceFactory.java
package xyz.serviceprovider;
import java.util.Hashtable;
import javax.naming.Context; import
javax.naming.Name; import javax.naming.Reference; import
javax.naming.spi.ObjectFactory;
//数据库服务对象工厂类被JNDI提供者调用来创建数据库服务实例,对
使用JNDI的客户不可见。 public class SimpleDBServiceFactory implements
ObjectFactory {
//根据Reference中存储的信息创建出SimpleDBService实例 public
Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable<?,
?> env) throws Exception { if(obj instanceof Reference){ Reference
ref=(Reference)obj; String
location=(String)ref.get("location").getContent(); String
state=(String)ref.get("state").getContent(); SimpleDBService db=
new SimpleDBService(); db.setProperty(0, location); db.setProperty(1,
state); return db; } return null; } }
♦
日志服务接口实现 SimpleLogService.java
package
xyz.serviceprovider;
import java.text.SimpleDateFormat; import
java.util.Date;
import javax.naming.NamingException; import
javax.naming.Reference; import javax.naming.Referenceable;
import xyz.service.LogService;
public class SimpleLogService
implements Referenceable, LogService { private SimpleDateFormat
sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//SimpleLogService没有任何属性,通过
SimpleLogService类名创建出来的SimpleLogService实例都是一样的, //因此这里无需添加RefAddr了。 public
Reference getReference() throws NamingException { return new
Reference(getClass().getName(),SimpleLogServiceFactory.class.getName(),null); }
public void log(String
message) { String date=sdf.format(new Date()); System.out.println(date+":"+message); } }
|