JNDI和数据源

老吴2018-09-02 17:39笔记4617浏览


版权声明:本篇文章为原创文章,转载请注明出处。https://yao2san.com/article/1302

什么是JNDI

JNDI:Java name directory interface,Java命名和目录接口。具体是什么,因为自己还不是特别熟悉,就不强行解释了,引用以下一段话解释:

JDBC和JNDI都是一种规范,是一组统一的API,里面包含了一组接口规范要求服务提供商来实现,包含了一组应用规范供编程人员使用,这样的好处是有利于编程人员可以用同一种方式来访问不同的数据库,使用同一种方式来方式来访问命名和目录服务,这里的同一种方式就是JDBC和JNDI提供的API,比如JDBC中的Connection等,JNDI中的Context等,并不是连接数据库或者使用命名和目录服务的方式对于各个数据库管理系统或者命名和目录服务提供者来说都是一样的,只是JDBC和JNDI提供另外的接口规范要求这些提供商来实现,比如各个数据库系统提供的驱动jar包,tomcat和JBoss容器各自配置Resouce的方式等,也就是说对编程人员隐藏了具体连接数据库或访问命名和目录服务的细节,让编程人员只需要关注自己的开发,即使后面换了数据库系统,换了web服务器等,应用程序依然不需要改变,只需要改变JDBC和JNDI的实现,这正是java平台无关性的表现~

对JDBC来说,要使用的服务只有:连接并与数据库交互。所以JDBC不论理解还是使用都是比较简单。
对JNDI来说,可供使用的服务包括命名和目录服务,命名服务允许编程人员通过名称查找对象,目录服务是命名服务的扩展,目录服务中的对象不单有名称还有属性,也就是可以利用属性来查找对象。而且命名和目录服务种类并不唯一:DNS、XNam 、Novell目录服务、LDAP、 CORBA对象服务、文件系统、Windows XP/2000/NT/Me/9x的注册表、RMI、DSML v1&v2、NIS。所以JNDI比JDBC要复杂蛮多。网上见过的最多的关于JNDI的使用例子,就是tomcat或者Jboss容器配置数据源,然后应用程序通过JNDI命名服务查找数据源,这也许是最典型的应用了。

什么是命名服务?

命名服务在一个集中位置存储信息,这样用户、计算机和应用程序便可通过网络进行通信。命名服务使用名称查找对象,而不是对象的物理ID。比如说在tomcat中查找JDBC数据源不是通过数据源的直接引用查找,而是通过JNDI与数据源绑定的名称查找,比如说通过DNS可以使用域名来访问Web应用,而不是直接通过输入Web服务器的IP地址来访问,这里的数据源的引用和IP地址都可以看作是资源的物理ID。命名服务有DNS,NIS,LDAP等。DNS称为域名系统,开发 DNS 后,网络中的计算机可由通用名称而非 Internet (IP)地址来标识。NIS称为网络信息服务,NIS 的主要作用是通过对各种网络信息进行集中控制来更好地管理网络。NIS 存储有关网络、计算机名称和地址、用户、以及网络服务的信息。LDAP还没去了解。

什么是目录服务?

目录服务是命名服务的扩展,目录服务的对象不单有名称,还有属性,既可以通过名称查找对象,也可以通过属性查找到一批对象然后筛选出自己需要的对象。目录服务应该比命名服务更广发,它可以将整个网络中的资源和设备组织起来,形成一个大的目录,然后通过目录就可以定位资源和设备,实现集中管理。

tomcat或Jboss的数据源属于什么服务?

属于命名服务,因为tomcat和Jbosss容器提供了命名服务或者目录服务,然后编程人员想用使用它们的服务时假如没有JNDI则必须遵照它们定的规范来开发,显然两个容器的使用服务的方法是不一样的,所以才有JNDI的规范。也就是说命名和目录服务并不是因为编程而存在的,而是Web容器本身就具有的。

简单来说就是对一些分散的东西进行集中化管理,使得调用者不用关心被调用的具体实现和位置。说白了也就是分离和解耦的思想。

JNDI最常用的就是配置数据源,对于Oracle来说,可以直接在控制台配置JNDI数据源,然后在.xml文件中增加一点配置就好,这里不细说了。对于Tomcat来说,一般可以在tomcat/conf/context.xml中配置,也可以在项目文件的WETA-INF目录下创建context.xml文件进行配置。

在Tomcat中使用JNDI配置数据源

1.在项目下配置

在META-INF文件下新建文件context.xml(文件名必须是这个),添加如下内容:

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <Resource name="jndi/test"
              auth="Container"
              type="javax.sql.DataSource"
              driverClassName="com.mysql.jdbc.Driver"
              url="jdbc:mysql://localhost:3306/db_name"
              username="root"
              password="******"
              maxActive="20"
              maxIdle="10"
              maxWait="10000"/>
</Context>

不需要在web.xml中配置<resource-ref>。

然后测试一下,通过JNDI使用上边配置的数据源:

public class JNDITest extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Context ctx;
        DataSource ds = null;
        try {
            ctx = new InitialContext();
            ds = (DataSource) ctx.lookup("java:comp/env/jndi/test");
            Connection conn = null;
            try {
                conn = ds.getConnection();
                System.out.println(conn.isClosed());
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

        } catch (NamingException e) {
            e.printStackTrace();
        }

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

因为需要用到web环境,所以不能直接在main方法中测试。

其中:

ctx.lookup("java:comp/env/jndi/test");

是通过资源名称查找。

java:comp/env/不可省略,否则报错。它表示一个上下文环境路径。

2.在tomcat中配置

和在项目下配置一样,只是将配置文件中的内容放到了tomcat/conf/context.xml中,这样做的好处是所有项目都可以使用。

(对于数据源、连接池、JNDI三者之间的关系还不是很清晰,老是觉得很相似,尤其反映到代码层面,例如在contex.xml中配置的Resource到底是数据源还是连接池呢,好像都对,那还需要DBCP或C3P0嘛?这个疑问等清醒一下在思考吧)

赞一个! (6)

文章评论(如需发表图片,请转至留言)