一、JNDI在Java EE中的应用 下面以一个常见的J2EE应用场景来看四种角色(组件接口、容器、组件提供者、应用程序)是如何围绕JNDI来发挥作用的: Java EE容器 |
众多数据库厂商提供了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 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);
}
}
日志服务对象工厂类 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工程):
相关推荐
2. **JNDI实例化** 在应用程序中,你可以通过JNDI查找刚创建的数据源。以下是一个简单的Java代码示例: ```java Context initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup("java:...
本实例将深入讲解如何利用JNDI进行数据库操作,以及数据源在数据库操作中的角色。 首先,JNDI的主要作用是为应用程序提供了一个统一的接口,用于查找和绑定资源。这些资源可以是数据库连接、邮件服务器、对象工厂等...
Tomcat 6.0 通过 JNDI 连接 MySQL 实例 Tomcat 6.0 中通过 JNDI 连接 MySQL 实例需要进行详细的配置和设置。本文将对 Tomcat 6.0 中的 JNDI 连接 MySQL 实例进行详细的介绍和解释。 配置 JNDI 资源 在 Tomcat 6.0...
在Java世界中,JNDI(Java Naming and Directory Interface)是一种标准接口,它允许应用程序查找和绑定各种命名和目录服务。这个技术的核心理念是提供一个统一的接口来访问不同的资源,比如数据库连接、EJB...
本实例是一个关于如何在Tomcat 6.0中配置和使用JNDI数据源的经典示例,包含了所需的JAR包、配置文件和SQL脚本。 首先,我们来看配置JNDI数据源的步骤。在Tomcat的`conf/server.xml`文件中,你需要添加一个新的`...
在这个实例中,我们将讨论如何在基于Tomcat的Web服务器上使用JNDI来创建数据库连接池。 首先,理解JNDI的工作原理至关重要。JNDI的核心是名称绑定,即将一个名称(比如“jdbc/myDataSource”)与一个对象(如数据库...
把文件用weblogic部署上去,然后反编译jar中的bind类 执行主方法weblogic就有打印出hello ejb的字样了,很好的一个ejb实例。
这个“log4j\c3p0\jndi详细配置实例”可能是包含了一个演示如何整合这三个技术的示例项目。下面将分别介绍这三个关键概念及其配置。 **1. log4j** `log4j`是Apache的一个开源项目,提供了一种灵活的日志记录系统。...
本文将深入探讨JNDI的使用实例,帮助开发者更好地理解和应用这一技术。 首先,我们需要了解JNDI的基本概念。JNDI是一个服务提供商接口(SPI),允许应用程序查找和操作存储在不同类型的命名和目录系统中的数据。...
- **全局JNDI树**:EJB家谱查找通过HA-JNDI,总是委托给本地JNDI实例。 7. **无状态会话Bean集群**: - **动态负载平衡**:通过配置实现Home和Remote接口的负载平衡策略。 - **自动故障转移**:服务器拓扑变化时...
8. **JNDI与EJB和JDBC**:在Enterprise JavaBeans (EJB) 中,JNDI用于查找和注入EJB实例。在Java Database Connectivity (JDBC) 中,数据源通常通过JNDI查找来获取,这样可以轻松地在不同环境中配置数据库连接。 9....
JBoss集群架构中,Home和Remote接口的查找通过HA-JNDI实现,确保始终指向本地JNDI实例。对于无状态会话Bean,可以通过自定义的动态负载平衡策略(如RoundRobin)进行分发。在服务器拓扑变化时,客户端网关会自动适应...
这通常涉及以下步骤:首先,创建一个新的`InitialContext`实例,然后调用`lookup()`方法,传入之前绑定的数据源名称,例如"mydata",来查找数据源。查找成功后,可以从中获取`Connection`对象,进而执行SQL查询和...
这个"JNDI简单应用示例"可能是演示如何使用JNDI进行基本操作的代码实例,例如: 1. **初始化Naming Context**:首先,你需要创建一个初始上下文(InitialContext),这是所有JNDI操作的起点。这通常通过传递一个...
- **松耦合**:JNDI允许应用程序与资源之间保持松散耦合,因为它们之间的联系是通过名称而不是硬编码的实例引用。 - **可扩展性**:随着系统的发展,可以轻松添加新的命名或目录服务,而无需修改现有代码。 - **集中...
应用中通过`InitialContext`查找这个JNDI名,即可获取到数据源实例,然后通过数据源获取数据库连接。 总结来说,JNDI连接池是Java应用中管理数据库连接的重要工具,它利用JNDI的抽象特性,结合连接池技术,实现了...
- **定义**:每台服务器维护自己的JNDI实例,这种方式可能会影响数据的一致性。 - **应用场景**:适用于对性能要求较高且能够接受一定程度的数据不一致性的场景。 **5.3 中央集中JNDI** - **定义**:所有服务器...
- **EJB Home Stub及EJB环境变量**:在EJB(Enterprise JavaBeans)环境中,JNDI用来查找EJB的Home接口,以及EJB实例的环境配置信息。 - **JDBC DataSource**:用于查找和管理数据库连接资源。 - **JMS Connection ...
为了解决这一问题,可以通过显式设置环境属性来创建`InitialContext`实例: ```java Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory"); env....