`

JNDI在Java EE中的应用

    博客分类:
  • JAVA
阅读更多

一、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.apache.org/tomcat-5.5-doc/jndi-datasource-examples-howto.html
关于在Tomcat中如何配置其他JNDI服务,可以参考文档:
http://tomcat.apache.org/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.sun.com/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 SimpleDBServiceF

actory 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);
}
}

 


日志服务对象工厂类 SimpleLogServiceFactory.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;

public class SimpleLogServiceFactory implements ObjectFactory {

public Object getObjectInstance(Object obj, Name name, Context ctx,
Hashtable<?, ?> env) throws Exception {
if(obj instanceof Reference){
return new SimpleLogService();
}
return null;
}
}

 

4、JNDI容器和JNDI客户端
最后,我们在JNDI应用package(xyz.jndi)中实现一个JNDI容器JNDIContainer和一个JNDI客户端应用JNDIClient。
JNDIContainer在内部使用文件系统服务提供者fscontext来提供命名和目录服务,配置文件JNDIContainer.properties是服务注入场所,供配置DBService和LogService实现。

JNDI容器类 JNDIContainer.java

package xyz.jndi;

import java.io.InputStream;
import java.util.Hashtable;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import xyz.service.DBService;
import xyz.service.LogService;

public class JNDIContainer {

private Context ctx=null;

public void init() throws Exception{
//初始化JNDI提供者。
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL, "file:/c:/sample"); //fscontext的初始目录,我们需要在c:\下创建sample目录。
ctx=new InitialContext(env);
loadServices();
}

//从配置文件JNDIContainer.properties中读取DBService和LogService实现,绑定到Context中。
private void loadServices() throws Exception{
InputStream in=getClass().getResourceAsStream("JNDIContainer.properties");
Properties props=new Properties();
props.load(in);

//inject dbservice
String s=props.getProperty("DBServiceClass");
Object obj=Class.forName(s).newInstance();
if(obj instanceof DBService){
DBService db=(DBService)obj;
String[] ss=props.getProperty("DBServiceProperty").split(";");
for(int i=0;i<ss.length;i++)
db.setProperty(i, ss[i]);
ctx.rebind(props.getProperty("DBServiceName"), db);
}

//inject logservice
s=props.getProperty("LogServiceClass");
obj=Class.forName(s).newInstance();
if(obj instanceof LogService){
LogService log=(LogService)obj;
ctx.rebind(props.getProperty("LogServiceName"), log);
}
}

public void close() throws NamingException{
ctx.close();
}

public Context getContext(){
return ctx;
}
}

 

 

JNDI容器配置文件 JNDIContainer.properties

 

//和JNDIContainer.java文件位于同一目录
DBServiceName=DBService
DBServiceClass=xyz.serviceprovider.SimpleDBService
DBServiceProperty=mydb//192.168.1.2:8421/testdb;start

LogServiceName=LogService
LogServiceClass=xyz.serviceprovider.SimpleLogService

 

 

JNDI客户端 JNDIClient.java

package xyz.jndi;

import javax.naming.Context;

import xyz.service.DBService;
import xyz.service.LogService;

public class JNDIClient {

public static void main(String[] args){
try{
JNDIContainer container=new JNDIContainer();
container.init();

//JNDI客户端使用标准JNDI接口访问命名服务。
Context ctx=container.getContext();
DBService db=(DBService)ctx.lookup("DBService");
System.out.println("db location is:"+db.getLocation()+",state is:"+db.getState());
db.accessDB();

LogService ls=(LogService)ctx.lookup("LogService");
ls.log("this is a log message.");

container.close();
}
catch(Exception e){
e.printStackTrace();
}
}
}

至此,我们的整个Java SE应用已经完成。下面是整个应用的源代码结构(Eclipse工程):

分享到:
评论

相关推荐

    java jndi的使用

    在Java应用中,JNDI通常与Java EE服务器结合使用,用于管理数据源。例如,通过JNDI,我们可以查找在服务器中注册的数据源,然后获取数据库连接,从而实现数据库的访问。在给定的描述中提到的"博文链接"可能详细阐述...

    精通Java EE:精通Java EE 整合应用案例\源代码第五章

    《精通Java EE:精通Java EE 整合应用案例》是一本深入探讨Java企业级开发的专著,其第五章的源代码着重展示了如何在实际项目中整合和运用Java EE技术。这一章节的内容涵盖了多种Java EE核心组件的实战应用,旨在...

    JAVA EE中文文档

    JNDI提供了一个统一的接口,让JAVA EE应用能够查找和绑定资源,如EJB、数据源等。这使得应用可以灵活地管理和使用服务器提供的服务。 **8. JTA(Java Transaction API)** JTA是JAVA EE的一部分,用于处理分布式...

    Java EE期末考试试题

    在Java EE应用中,理解如何通过JNDI查找和绑定资源,是高级话题,可能会出现在期末考试中。 7. **JTA (Java Transaction API)**: 事务管理是Java EE应用中不可或缺的一部分。JTA用于管理分布式事务,确保数据的一致...

    轻量级Java EE企业应用实战第三版第二章源码

    通过阅读和实践本章的源码,你可以学习到如何使用上述技术来构建一个简单的Java EE应用,包括从初始化环境、编写代码到部署运行的全过程。这将为你后续深入学习Java EE的其他高级特性和框架打下坚实基础。

    java EE 中文帮助文档

    Java EE(Java Platform, Enterprise Edition)是Java平台上用于构建企业级应用的开发框架。它提供了一整套服务和API,让开发者能够构建可扩展、安全且高性能的分布式应用程序。中文帮助文档是Java EE开发者的重要...

    经典JAVA.EE企业应用实战.基于WEBLOGIC_JBOSS的JSF_EJB3_JPA整合开发.pdf

    此外,作者李刚在Java EE应用开发领域拥有超过10年的经验,其著作不仅覆盖了企业级Java应用开发的基础知识和进阶技能,还包括了作者在多年实际工作中积累的宝贵经验。李刚老师曾经担任过LITEON公司J2EE技术主管,...

    Java EE Web编程(Eclipse平台)源文件

    6. **DAO(Data Access Object)**模式:在Java EE应用中,DAO是访问数据库的标准设计模式,封装了SQL操作,使得业务逻辑与数据访问层解耦。 7. **MVC(Model-View-Controller)**架构:一种流行的设计模式,将应用...

    Java EE企业级应用开发(笔试).zip

    现代Java EE应用中,主要关注无状态会话bean(Stateless Session Beans)和消息驱动bean(Message-driven Beans)。 4. **JPA(Java Persistence API)与Hibernate**:JPA是Java EE提供的ORM(对象关系映射)标准,...

    java ee教程(电子教案)

    7. **CDI(Contexts and Dependency Injection)**:CDI为Java EE应用提供依赖注入和上下文管理,简化组件之间的依赖关系和生命周期管理。 8. **WS(Web Services)**:Java EE支持SOAP和RESTful两种类型的Web服务...

    JNDI配置数据源在java web开发中的使用

    在Java EE环境中,数据源通常由应用服务器提供,如Tomcat、WebLogic、JBOSS等,它们预先配置好并注册到JNDI上下文中,供应用通过JNDI查找使用。 3. **配置数据源** 在不同的应用服务器中,配置数据源的方法略有...

    Java EE基础实用教程[郑阿奇]

    在Java EE环境中,JNDI常用于在应用服务器中查找和管理各种服务和资源。 在郑阿奇的《Java EE基础实用教程》中,读者可以期待深入浅出地了解这些技术,包括它们的工作原理、配置方法以及如何在实际项目中应用。此外...

    java 采用JNDI访问数据库(三种方法)

    在Java EE应用服务器(如Tomcat、JBoss、WebLogic、GlassFish等)中,数据源通常会被配置为一个JNDI资源。开发者无需直接处理数据库连接的创建和关闭,只需通过JNDI查找即可获取连接。 1. **配置数据源**:在应用...

    java EE帮助文档

    Java EE(Java Platform, Enterprise Edition),也常被称为J2EE,是Java技术在企业级应用开发中的核心框架。它提供了一系列标准和API,用于构建分布式、多层的企业级应用程序,涵盖了从数据库连接、Web服务到安全...

    java EE编程技术

    在Java EE中,它常用来查找和绑定Java Enterprise Beans (EJB)。EJB是Java EE的一种服务器端组件,用于实现业务逻辑,提供了事务管理、安全性和资源池等功能。 4. **JDBC与DAO** JDBC(Java Database Connectivity...

    精通Java EE:精通Java EE 整合应用案例随书光盘案例数据库部分

    8. **JNDI(Java Naming and Directory Interface)**:提供命名和目录服务,便于查找和管理Java EE应用中的资源。 光盘中的数据库部分可能包含以下内容: - 数据库设计:包括ER图(实体关系图),表结构设计,...

    JAVA-EE-api-5.0-中英文对照经理版.chm.7z

    这个“JAVA-EE-api-5.0-中英文对照经理版”的文档是学习和开发Java EE 5.0应用的重要参考资料,它详细地解释了上述API的使用方法和概念,无论是初学者还是经验丰富的开发者,都能从中获益匪浅。同时,由于提供了中...

    精心整理的Java EE API中文版帮助文档!!

    Java EE(Java Platform, Enterprise Edition)是Java平台上用于构建企业级应用的标准规范,它提供了丰富的API和服务,使得开发者能够创建可扩展、安全且高效的分布式应用程序。这个压缩包包含的中文版帮助文档对于...

    Java EE基础实用教程 代码

    在Java EE应用中,JNDI常用来查找和绑定EJB或数据源。 9. **JTA(Java Transaction API)**:提供跨多个资源的事务管理,确保数据一致性。在多层架构中,事务管理是至关重要的。 10. **Filter和Listener**:在Java...

Global site tag (gtag.js) - Google Analytics