JNDI

JNDI基础

一 简介

1.JNDI:Java Naming and Directory Interface,即Java命名和目录接口。JNDI包含了一些标准API接口,Java程序可以通过这些接口来访问命名目录服务。JNDI不依赖于任何独立的命名目录服务器,不管采用哪种命名目录服务器,应用程序都可以通过统一的JNDI接口来调用。要使用JNDI,必须要安装jdk 1.3以上版本。

2.命名服务:就是将名字和计算机系统内的一个对象建立关联,从而允许应用程序通过该名字访问该对象。简而言之,命名服务就是为计算机系统内的对象起名字。

例如在Internet上的域名服务 (domain naming service,DNS) 就是提供将域名映射到IP地址的命名服务,在打开网站时一般都是 在浏览器中输入名字,通过DNS找到相应的IP地址,然后打开。所有的因特网通信都使用TCP、UDP或IP协议。IP地址由4个字节32位二进制数字组成,数字和名字相比,对于人来说名字比数字要容易记忆,但对于计算机来讲,它更善于处理数字。

其实所有的命名服务都提供DNS这种基本功能,即一个系统向命名服务注册,命名服务提供一个值到另一个值的映射。然后,另外一个系统访问命名服务就可以取得映射信息。这种交互关系对分布式企业级应用来讲显得非常重要。

3.目录服务:目录服务是命名服务的拓展,目录服务不仅需要保存名称和对象的关联,还要保存对象的各种属性,这样就允许开发者操作对象的属性,包括增删改查对象的属性。在目录服务中,你可以根据属性搜索对象。JNDI允许你访问文件系统中的文件,定位远程RMI注册的对象,访问象LDAP这样的目录服务,定位网络上的EJB组件。从我们日常生活中去理解目录服务的概念可以从电话簿说起,电话簿本身就是一个比较典型的目录服务,如果你要找到某个人的电话号码,你需要从电话簿里找到这个人的名称,然后再看其电话号码。

4.JNDI结构

JNDI结构包括JNDI API和JNDI SPI

开发者通过JNDI API以一致的方式来访问各种命名服务、目录服务,而JNDI API则保证各种命名服务、目录服务透明的加入JNDI结构中,Naming Manager则负责管理二者之间的转换。。

在开发企业级应用时,JNDI显得尤其重要:客户端代码可以通过JNDI来访问EJB,客户端代码需要通过JNDI来访问容器管理的数据源......Java EE应用中所有远程对象都需要通过JNDI来访问。

二 使用JNDI配置数据源

1.数据源的由来

在Java开发中,使用JDBC操作数据库的四个步骤如下:

加载数据库驱动程序(Class.forName("数据库驱动类");)

连接数据库(Connection con  = DriverManager.getConnection();)

操作数据库(PreparedStatement stat = con.prepareStatement(sql);stat.executeQuery();)

关闭数据库,释放连接(con.close();)

也就是说,所有的用户都需要经过此四步进行操作,但是这四步之中有三步(加载数据库驱动程序、连接数据库、关闭数据库,释放连接)对所有人都是一样的,而所有人只有在操作数据库上是不一样,那么这就造成了性能的损耗。

那么最好的做法是,准备出一个空间,此空间里专门保存着全部的数据库连接,以后用户用数据库操作的时候不用再重新加载驱动、连接数据库之类的,而直接从此空间中取走连接,关闭的时候直接把连接放回到此空间之中。

那么此空间就可以称为连接池(保存所有的数据库连接),但是如果要想实现此空间的话,则必须有一个问题要考虑?

如果没有任何一个用户使用连接,那么那么应该维持一定数量的连接,等待用户使用。

如果连接已经满了,则必须打开新的连接,供更多用户使用。

如果一个服务器就只能有100个连接,那么如果有第101个人过来呢?应该等待其他用户释放连接

如果一个用户等待时间太长了,则应该告诉用户,操作是失败的。

直接用程序实现以上功能,则会比较麻烦,所以在Tomcat 4.1.27之后,在服务器上就直接增加了数据源的配置选项, 直接在服务器上配置好数据源连接池即可。在J2EE服务器上保存着一个数据库的多个连接。每一个连接通过DataSource可以找到。DataSource被绑定在了JNDI树上(为每一个DataSource提供一个名字)客户端通过名称找到在JNDI树上绑定的DataSource,再由DataSource找到一个连接。如下图所示:

那么在以后的操作中,除了数据库的连接方式不一样之外,其他的所有操作都一样,只是关闭的时候不是彻底地关闭数据库,而是把数据库的连接放回到连接池中去。

2.在tomcat中配置JNDI

主要包括三种方式:web.xml    context.xml    server.xml

这三种的区别是,server.xml与context.xml类似都是所有应用通用的,但是context.xml只是把它分离出来单独形成了一个文件而已。在WEB-INF/下的context.xml则是应用自己的,所以如果不想把某些信息公开,放在这里就可以了。

(1)server.xml方式

这种方式设置的是全局JNDI配置,在server.xml下配置你必需重启服务器才能生效,而context.xml配置保存后tomcat会自动加载无需重启。

Step1:在tomcat服务器的lib目录下加入数据库连接的驱动jar包,如

mysql-connector-java-5.1.27.jar  -->mySql数据库的jar包

ojdbc14.jar   -->Oracle数据库的jar包

sqljdbc4.jar   -->SQLServer数据库的jar包

Step2:

(1)server.xml方式

修改tomcat服务器的conf目录下的server.xml配置文件

在server.xml配置文件中有一个自带的全局JNDI配置,如图:

在server.xml中添加全局JNDI数据源配置,在<GlobalNamingResources>下继续添加<Resource>标签,常见的几个数据库的配置如下所示:

<!--配置Oracle数据库的JNDI数据源-->

<Resource

name="jdbc/oracle"

auth="Container"

type="javax.sql.DataSource"

maxActive="100"

maxIdle="30"

maxWait="10000"

username="lead_oams"

password="p"

driverClassName="oracle.jdbc.driver.OracleDriver"

url="jdbc:oracle:thin:@192.168.1.229:1521:lead"/>

<!--配置MySQL数据库的JNDI数据源-->

<Resource

name="jdbc/mysql"

auth="Container"

type="javax.sql.DataSource"

maxActive="100"

maxIdle="30"

maxWait="10000"

username="root"

password="root"

driverClassName="com.mysql.jdbc.Driver"

url="jdbc:mysql://192.168.1.144:3306/leadtest?useUnicode=true&amp;characterEncoding=utf-8"/>

<!--配置SQLServer数据库的JNDI数据源-->

<Resource

name="jdbc/sqlserver"

auth="Container"

type="javax.sql.DataSource"

maxActive="100"

maxIdle="30"

maxWait="10000"

username="sa"

password="[email protected]"

driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"

url="jdbc:sqlserver://192.168.1.51:1433;DatabaseName=demo"/>

其中,name:表示以后要查找的名称。通过此名称可以找到DataSource,此名称任意更换,但是程序中最终要查找的就是此名称,为了不与其他的名称混淆,所以使用jdbc/oracle,现在配置的是一个jdbc的关于oracle的命名服务。

auth:由容器进行授权及管理,指的用户名和密码是否可以在容器上生效

type:此名称所代表的类型,现在为javax.sql.DataSource

maxActive:表示一个数据库在此服务器上所能打开的最大连接数

maxIdle:表示一个数据库在此服务器上维持的最小连接数

maxWait:最大等待时间。10000毫秒

(2)context.xml方式

选择你所要连接的数据库,打开comcat下的config里的context.xml,将<resource>下的内容复制过去

<Context>

<WatchedResource>WEB-INF/web.xml</WatchedResource>

<Resource

name="jdbc/mysql"

auth="Container"

driverClassName="com.mysql.jdbc.Driver"

type="javax.sql.DataSource"

maxActive="100"

maxIdle="30"

maxWait="10000"

username="root"

password="123456"

url="jdbc:mysql://localhost:3306/mydb?useUnicode=true&amp;characterEncoding=utf-8"/>

</Context>

Step3:测试

在项目的WEB-INF的web.xml文件中添加JNDI配置的资源引用:

<!--Oracle数据库JNDI数据源引用 -->

<resource-ref>

<description>Oracle DB Connection</description>

<res-ref-name>oracleDataSource</res-ref-name>

<res-type>javax.sql.DataSource</res-type>

<res-auth>Container</res-auth>

</resource-ref>

<!--MySQL数据库JNDI数据源引用 -->

<resource-ref>

<description>MySQL DB Connection</description>

<res-ref-name>mysqlDataSource</res-ref-name>

<res-type>javax.sql.DataSource</res-type>

<res-auth>Container</res-auth>

</resource-ref>

<!--SQLServer数据库JNDI数据源引用 -->

<resource-ref>

<description>SQLServer DB Connection</description>

<res-ref-name>sqlserverDataSource</res-ref-name>

<res-type>javax.sql.DataSource</res-type>

<res-auth>Container</res-auth>

</resource-ref>

JNDI配置的资源引用包括:

res-ref-name:表示引用资源的名称

res-type:此资源对应的类型为javax.sql.DataSource

res-auth:容器授权管理

(2)编写测试内容

<%@ page import="java.sql.*,javax.sql.*,javax.naming.*"  %>

<%

Connection conn=null;

try

{

//初始化查找命名空间

Context ctx = new InitialContext();

//InitialContext ctx = new InitialContext();亦可

//找到DataSource,对名称进行定位java:comp/env是必须加的,后面跟你的DataSource名

DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/mysql");

//取出连接

conn = ds.getConnection();

System.out.println("connection pool connected !!");

} catch (NamingException e) {

System.out.println(e.getMessage());

} catch (SQLException e) {

e.printStackTrace();

}finally {

if(conn!=null) {

try {

conn.close();

} catch(SQLException e) { }

}

}

%>

报错:org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot create JDBC driver of class ‘‘ for connect URL ‘null‘

三 JNDI常用操作

1.JNDI架构提供了一组标准命名系统的API,这些API在JDK1.3之前是作为一个单独的扩展包jndi.jar(通过这个地址下载),这个基础API构建在与SPI之上。这个API提供如下五个包javax.naming,javax.naming.directory,javax.naming.event,javax.naming.ldap,javax.naming.spi

2.通过JNDI来访问被绑定对象要按一下操作:

(1)创建Context对象

(2)调用Context的lookup方法根据JNDI名称查找被绑定对象;或者调用bind方法来执行绑定;或者调用unbind方法来解除绑定...就是调用Context的方法来执行绑定、查找等操作。

(3)关闭Context

3.Context只是一个接口,通常会使用它的实现类InitialContext来创建实例。InitialContext提供了两个构造器:

InitialContext():读取系统属性作为Context属性来创建InitialContext

InitialContext(Hashtable<?,?> environment):以environment参数指定的属性作为Context属性来创建InitialContext

如果创建InitialContext对象时没有传入任何参数,那么它必须能从系统属性(System.getProperties()方法返回值)中读到合适的Context属性来执行初始化,否则它将抛出NoInitialContextException异常。

在JSP页面中执行以下代码:

<%

Properties props=System.getProperties();

for(String name:props.stringPropertyNames()){

out.println(name+"--->"+props.getProperty(name)+"<br/>");

}

%>

会看到如下的结果:

由此可见,当在服务器环境下的Web应用中创建InitialContext时,由于服务器启动时已经添加了它所需的系统属性,因此直接创建InitialContext()就可以了。

Hashtable至少包含如下两个key:

java.naming.factory.initial:可用Context内的INITIA_CONTEXT_FACTORY常量代替,该key的值应该为初始化Context的工厂类。

java.naming.providor.url:可用Context内的PROVIDER_URL常量代替,该key的值应该为Context服务提供者的URL

4.举例

以文件系统的JNDI为例,创建如下InitialContext对象:

public class myTest {

public static void main(String[] args) throws NamingException {

final String fileName="lyy.doc";

Hashtable env=new Hashtable();

env.put(Context.INITIAL_CONTEXT_FACTORY,"org.apache.naming.java.javaURLContextFactory");

env.put(Context.PROVIDER_URL, "file:/d:/wscite");

Context ctx=new InitialContext(env);

Object file=ctx.lookup(fileName);

System.out.println(fileName+"名称被绑定到:"+file);

ctx.close();

}

}

报错:java.lang.NoClassDefFoundError: org/apache/juli/logging/LogFactory

打开window->Preferences->你所用的jdk版本->edit->add external jars->选择tomact包里的bin的tomcat-juli.jar->添加

上面的程序将d:/wscite目录作为一个Context,然后以此Context来查找对应的名称。对于文件系统的JNDI来说,每个文件夹相当于一个Context,每个文件名相当于一个JNDI名,而文件对象则是实际被绑定的对象。

方法:

(1)查找对象

通过Context提供的lookup(jndi)方法来实现,该方法接受被绑定的JNDI名,返回与之绑定的对象

该方法只能返回一个Object类型的对象,因此要注意强制类型转换

(2)绑定

JNDI通过Context的bind(String name,Object obj)方法来执行绑定,第一个参数是被绑定的JNDI名,第二个参数是被绑定的对象

该方法就相当于为obj对象起了一个name

(3)重新绑定

rebind(String name,Object obj),如果该名称已被绑定,则是修改,如果没绑定就与bind功能相同。

时间: 2024-10-07 05:50:14

JNDI的相关文章

JNDI在Tomcat中的配置

使用JNDI获取连接对象 java:comp/env/jdbc/news 这段为固定写法java:comp/env/ 在Tomcat中的配置 配置在:context.xml文件内 F:\apache-tomcat-7.0.68-windows-x64\apache-tomcat-7.0.68\conf\context.xml ---------mySQL<Resource name="jdbc/news"auth="Container" type="

理解JNDI中 java:comp/env/jdbc/datasource 与 jdbc/datasource 的不同之处(转)

在描述JNDI,例如获得数据源时,JNDI地址有两种写法,例如同是  jdbc/testDS 数据源: A:java:comp/env/jdbc/testDS B:jdbc/testDS   这两种写法,配置的方式也不尽相同,第一种方法应该算是一种利于程序移植或迁移的方法,它的实现与“映射”的概念相同,而B方法,则是一个硬引用. java:comp/env 是环境命名上下文(environment naming context(ENC)),是在EJB规范1.1以后引入的,引入这个是为了解决原来J

JPA, JNDI, OSGi

JPA Java Persistence API.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中. JNDI Java Naming and Directory Interface,Java命名和目录接口,是SUN公司提供的一种标准的Java命名系统接口,JNDI提供统一的客户端API,通过不同的访问提供者接口JNDI服务供应接口(SPI)的实现,由管理者将JNDI API映射为特定的命名服务和目录系统,使得Java应用程序可以和这些命名服务

JNDI深入浅出

1.什么是JNDI JNDI(The Java Naming and Directory Interface,Java命名和目录接口)是一组在Java应用中访问命名和目录服务的API.命名服务将名称和对象联系起来,使得我们可以用名称访问对象.目录服务是一种命名服务,在这种服务里,对象不但有名称,还有属性. 命名或目录服务使你可以集中存储共有信息,这一点在网络应用中是重要的,因为这使得这样的应用更协调.更容易管理.例如,可以将打印机设置存储在目录服务中,以便被与打印机有关的应用使用. 命名服务中的

Springmvc +JNDI 在Tomcat下 配置数据源(转)

一.             简介 jndi(Java Naming and Directory Interface,Java命名和目录接口)是一组在Java应用中访问命名和目录服务的API.命名服务将名称和对象联系起来,使得我们可以用名称访问对象.目录服务是一种命名服务,在这种服务里,对象不但有名称,还有属性. 二.             tomcat配置jndi有三种方式. 第一种:单个应用独享数据源 在Tomcat的server.xml找到工程的Context节点,添加一个私有数据源 <

tomcat配置JNDI获取数据源

各个web工程可以通过工程内的xml文件配置访问数据库的数据源,这样的配置是各个工程私有的.基于JNDI为tomcat配置数据源,则可以做成全局的,各工程只需要通过便签引用数据源即可. 1.需要将数据库的连接驱动mysql-connector-java-5.1.21.jar及数据库连接池的jar包druid-0.2.9.jar放到Tomcat 6.0\lib下. 2.修改tomcat的配置文件,基于JNDI配置数据源,Tomcat 6.0\conf\context.xml改成如下即可,原文件中多

JNDI 使用

J2EE技术规范(一)--JNDI 分类: java 基础2012-12-02 20:05 1539人阅读 评论(14) 收藏 举报 学习Java,我们首先要掌握的就是十三种技术规范,我们接下来就一步一步的来学习.今天主要是讲讲JNDI. 一.理解JNDI的用途: JNDI是用于访问不同的命名和目录服务的统一API接口. 二.那何时使用JNDI呢: (1)JNDI是一种查找服务,用于查找: Web应用环境变量 EJBs和它们的环境变量 通过DataSources的数据库连接池 JMS目标和连接工

Hibernate 异常 : Error parsing JNDI name [xxx]

初学 Hibernate ,用官方给的日志模板配置好了日志,跑起小例子, 控制台中的日志里写了一些异常: 21:16:36,036 DEBUG EntityLoader:146 -  Static select for entity cn.sjll.hibernate435.model.UserModel  [OPTIMISTIC_FORCE_INCREMENT]: select usermodel0_.ID as ID1_0_0_,  usermodel0_.NAME as NAME2_0_0

JNDI数据源的使用

有时候我们数据库的连接会使用jndi的方式 try { InitialContext ic = new InitialContext(); dataSource = (DataSource) ic.lookup("java:/comp/env/jdbc/murach"); } catch(Exception e) { e.printStackTrace(); } 各种不同的J2EE容器,都用不同的配置方式. tomcat可以配置全局JNDI和私有JNDI(注意这里说的Tomcat6):