由Tomcat下的JNDI数据源引出的......
??? 众所周知,Tomcat是支持数据库连接池的,并且还支持通过JNDI接口来获得这一服务。要想在你的程序中使用这一特性,需要你对Tomcat做一些配制。
??? 我以往的做法都是现到网上去找,然后人家说在哪个配制文件下加一段什么代码,就照着做,成功后这事儿也就结了。过了一段时间又遇到这个问题,还是同样的做法......。为了结束这种痛苦的、无休止的循环,我决定花点儿时间把这个问题搞清楚,要做到不仅要知其然还要知其所以然。
Tomcat的配制文件体系(以Tomcat 6.0.18为例)
??? 在%TOMCAT_HOME%/conf目录下一般会有server.xml、context.xml、web.xml、tomcat-users.xml等配制文件,下面重点说一下server.xml和context.xml两个文件:
1、server.xml
??? 这个文件是整个Tomcat的一个缩影,从它可以看出Tomcat的架构和工作方式。
Server(1)----元素代表了整个Catalina servlet容器
|
|------ Service(n)----元素代表了一个用于处理请求的组合,这个组合包括了一个或多个Connector和
|???????? | ? ? ? ? ? ? ? ? ? ?一个Engin,这些Connector共享这个Engin。?
|???????? |
|???????? |------ Connector(n)----主要用于监听来自client的请求,一个Connector监听一个端口。
|???????? |
|???????? |------ Engin(1)----元素代表了和一个特定联系的,用于请求处理的机构。它接受和
|?????????????????? |???????????????????? 处理来自同属一个Service下的所有Connector的请求,并生成完整的回应(response)
|?????????????????? |
|?????????????????? |------ Host(n)----元素代表了一个虚拟主机
|???????????????????????????? |
|???????????????????????????? |------ Context(n)----元素代表了一个特定的虚拟主机下的web application
|
|------ GlobalNamingResources(1)----元素定义的是整个容器级别的全局的资源,
??????????????????????????????????????????????????????????????????? 这些 资源对容器中的每个Web Application都是不可见的。
??????????????????????????????????????????????????????????????????? 某个Web Application想要使用某个全局资源,可以在此
??????????????????????????????????????????????????????????????????? Web Application的?? 元素下使用元素
???????????????????????????????????????????????????????????????????? 来引用想要使用的全局资源。
??? 在这想要说的主要是GlobalNamingResources这个节点。正如上面的说明所述,定义在它下面的资源都是整个容器级别的全局资源,也就是说这些资源可以被部署在这个容器中的所有webapp所使用。但是必须在webapp和这些资源之间搭一座桥------在webapp对应的Context节点下使用元素来引用想要使用的全局资源。
2、context.xml
??? 从上面我们可以知道一个Host(虚拟主机)下可以有多个Context,每个Context就代表了一个部署在该虚拟主机下的webapp。tomcat 5以后就不推荐大家在server.xml的Host节点下直接追加Context,因为对Host节点下的Context的修改,会导致server.xml改变这样一来就必须要重新起动服务器才能加载新的server.xml。所以在tomcat 5以后就多了context.xml这个文件,在这个文件下配制的资源所有webapp都能够访问到。
??? 以上是对tomcat做的一些粗略的介绍,回到正题,下面就tomcat下的JNDI数据源的配制来实践一下上面的说法。
方案一:使用%TOMCAT_HOME%/conf/context.xml
??? 直接上代码:
</Context> <Resource name="jdbc/test" type="javax.sql.DataSource" username="root" password="mysql" driverClassName="com.mysql.jdbc.Driver" maxIdle="2" maxWait="5000" url="jdbc:mysql://localhost:3306/test" maxActive="4"/></Context>
?
??????? 以上的<Resource>节点是针对MySql的数据源配制信息,以上工作做完后,Tomcat起动时就会把这个数据源生成好放到上下文环境中。该Tomcat下的所有webapp都能通过JNDI接口找到该数据源。
?
??? 这下东西有了,但怎么来找到并使用它呢?
?
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"><resource-ref> <description>TomcatJNDI数据源</description> <res-ref-name>jdbc/test</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth></resource-ref></web-app>
??? 以上是在自己的webapp下添加对配制在context.xml下的数据源的引用。试验了一下,在Tomcat 6.0.18下这个<resource-ref>不用,也能正确找到那个数据源。但最好还是写上吧!
?
??? 桥已经搭好了,来试着lookup一下吧!
?
public static Connection getConnection() { Connection conn = null; try { Context ctx = new InitialContext(); DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/test"); conn = ds.getConnection(); } catch (NamingException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } if(conn != null){ System.out.println("Connected!"); }else { System.out.println("Connect failed!"); } return conn; }??? 你"connected"了吗?
?
方案二:使用%TOMCAT_HOME%/conf/server.xml下的<GlobalNamingResources>节点。
??? 直接上代码:
<Server port="8005" shutdown="SHUTDOWN"><GlobalNamingResources><Resource name="jdbc/test" type="javax.sql.DataSource" factory="" password="mysql" driverClassName="com.mysql.jdbc.Driver" maxIdle="2" maxWait="5000" username="root" url="jdbc:mysql://localhost:3306/test" maxActive="4"/>...</GlobalNamingResources>...</Server>
??? 顾名思义,这也是面向所有webapp的。但跟方案一有所不同的是<GlobalNamingResources>需要跟<ResourceLink>配合使用。详细情况参见下面:
?
<Context><ResourceLink name="jdbc/link" global="jdbc/test" type="javax.sql.DataSource"/>...</Context>
??? 此时lookup时需要用"java:comp/env/jdbc/link"
??? Context ctx = new InitialContext();
??????????? DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/link");
?
方案三:<Host>节点下追加<context>节点。具体内容跟方案一类似,但tomcat5后就不推荐使用这种方法了。
?