|
一、JNDI在Java EE中的應(yīng)用 JNDI
技術(shù)是Java EE規(guī)范中的一個(gè)重要“幕后”角色,它為Java EE容器、組件提供者和應(yīng)用程序之間提供了橋梁作用:Java
EE容器同時(shí)扮演JNDI提供者角色,組件提供者將某個(gè)服務(wù)的具體實(shí)現(xiàn)部署到容器上,應(yīng)用程序通過標(biāo)準(zhǔn)的JNDI接口就可以從容器上發(fā)現(xiàn)并使用服務(wù),而不
用關(guān)心服務(wù)的具體實(shí)現(xiàn)是什么,它的具體位置在哪里。
下面以一個(gè)常見的J2EE應(yīng)用
場景來看四種角色(組件接口、容器、組件提供者、應(yīng)用程序)是如何圍繞JNDI來發(fā)揮作用的: 組件接口 數(shù)據(jù)源DataSource是一種很常見的服務(wù)。我們通常將組件接口綁定到容器的Context上供客戶調(diào)用。
Java EE容器 Tomcat是一種常見的Java
EE容器,其他的還有JBoss,WebLogic,它們同時(shí)也實(shí)現(xiàn)了JNDI提供者規(guī)范。容器通常提供一個(gè)JNDI注入場所供加入組件的具體實(shí)現(xiàn),比如
Tomcat中的Server.xml配置文件。
組件提供者 眾
多數(shù)據(jù)庫廠商提供了DataSource的實(shí)現(xiàn),比如OracleDataSource,MySQLDataSource,XXXDataSource
等。我們將該實(shí)現(xiàn)的部署到容器中:將一系列jar加入classpath中,在Server.xml中配置DataSource實(shí)現(xiàn),如: <Resource
name="jdbc/MyDB" auth="Container" type="javax.sql.DataSource" ..../>
應(yīng)用程序 一個(gè)JSP/Servlet應(yīng)用程序。通過JNDI接口使用
DataSource服務(wù),如: Context initContext = new InitialContext(); Context
envContext = (Context)initContext.lookup("java:/comp/env"); DataSource
ds = (DataSource)envContext.lookup("jdbc/MyDB");
關(guān)于在Tomcat中如何配置DataSource,可以參考文檔:http://tomcat./tomcat-5.5-doc/jndi-datasource-examples-howto.html。 關(guān)于在Tomcat中如何配置其他JNDI服務(wù),可以參考文檔:http://tomcat./tomcat-5.5-doc/jndi-resources-howto.html。
二、
JNDI實(shí)例演練:在Java SE中使用JNDI 要在Java
EE中環(huán)境中提供一個(gè)獨(dú)立的實(shí)例不太容易。下面以一個(gè)獨(dú)立的Java
SE應(yīng)用來演練JNDI的使用過程。在該應(yīng)用中,我們使用JNDI來使用兩種假想的服務(wù):數(shù)據(jù)庫服務(wù)DBService和日志服務(wù)LogService。
1、指定JNDI提供者 要使用JNDI,首先要配置JNDI提供者。在我們的
Java SE應(yīng)用中,沒有Java
EE容器充當(dāng)JNDI提供者,因此我們要指定其他的JNDI提供者。在我們的例子里,我們使用SUN的文件系統(tǒng)服務(wù)提供者File System
Service Provider。由于SUN的文件系統(tǒng)服務(wù)提供者并沒有包含在JDK中,我們需要從SUN網(wǎng)站上下載:http://java./products/jndi/downloads/index.html。它包含兩個(gè)jar文件:fscontext.jar和providerutil.jar。我們將這兩個(gè)文件加入項(xiàng)目的類
路徑中。
2、定義服務(wù)接口 首先,我們
在服務(wù)接口package(xyz.service)中定義服務(wù)接口:DBService和LogService,分別表示數(shù)據(jù)庫服務(wù)和日志服務(wù)。
♦
數(shù)據(jù)庫服務(wù)接口 DBService.java
package xyz.service;
public interface DBService { String
getLocation(); //獲取數(shù)據(jù)庫位置
String getState(); //獲取數(shù)據(jù)庫狀態(tài) void
accessDB(); //訪問數(shù)據(jù)庫 void setProperty(int index,String
property); //設(shè)置數(shù)據(jù)庫信息 }
♦日志服務(wù)接口 LogService.java
package xyz.service;
public interface LogService { void
log(String message); //記錄日志 }
3、組件提供者實(shí)現(xiàn)服務(wù)接口 接
下來,我們在組件提供者package(xyz.serviceprovider)中提供DBService和LogService的實(shí)
現(xiàn):SimpleDBService和SimpleLogService。為了讓服務(wù)能夠在JNDI環(huán)境中使用,根據(jù)JNDI規(guī)范,我們同時(shí)定義兩個(gè)對象
工廠類SimpleDBServiceFactory和SimpleLogServiceFactory,分別用來創(chuàng)建服務(wù)實(shí)例。
♦
數(shù)據(jù)庫服務(wù)接口實(shí)現(xiàn) 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;
//為了將數(shù)據(jù)庫服務(wù)實(shí)例加入JNDI的Context中,我們需要實(shí)
現(xiàn)Referenceable接口,并實(shí)現(xiàn)RetReference方法。 //關(guān)于Reference和Referenceable,請參考上一
篇:Java技術(shù)回顧之JNDI:JNDI API public class SimpleDBService implements
Referenceable, DBService { private String
location="mydb//local:8421/defaultdb";//數(shù)據(jù)庫服務(wù)屬性之一:數(shù)據(jù)庫位置 private
String state="start"; //數(shù)據(jù)庫服務(wù)屬性之二:數(shù)據(jù)庫狀態(tài)
public Reference getReference()
throws NamingException { //Reference是對象的引用,Context中存放的是Reference,為了
從Reference中還原出對象實(shí)例, //我們需要添加RefAddr,它們是創(chuàng)建對象實(shí)例的線索。在我們的
SimpleDBService中,location和state是這樣兩個(gè)線索。 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; } }
♦數(shù)據(jù)庫服務(wù)對象工廠類 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;
//數(shù)據(jù)庫服務(wù)對象工廠類被JNDI提供者調(diào)用來創(chuàng)建數(shù)據(jù)庫服務(wù)實(shí)例,對
使用JNDI的客戶不可見。 public class SimpleDBServiceFactory implements
ObjectFactory {
//根據(jù)Reference中存儲的信息創(chuàng)建出SimpleDBService實(shí)例 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; } }
♦
日志服務(wù)接口實(shí)現(xiàn) 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類名創(chuàng)建出來的SimpleLogService實(shí)例都是一樣的, //因此這里無需添加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); } }
|