最近做的一个项目中运用到了连接池技术,可能我们大家比较熟悉的开源连接池有dbcp,c3p0,proxool。对这三种连接池来说,从性能和出错率来说,proxool稍微比前两种好些。今天主要讲述一下,我在项目中成功的配置和源码。
第一步:首先去http://proxool.sourceforge.net/下载两个jar文件,一个是proxool-0.9.1.jar,另一个是proxool-cglib.jar,然后将这两个jar文件放到WEB-INF/lib下。
第二步:就是写一个单独的proxool.xml文件放到WEB-INF文件夹下。我用的数据库是Oracle10g。
<?xml version="1.0" encoding="UTF-8"?>
<something-else-entirely>
<proxool>
<!-- 连接池的名字 -->
<alias>dbPool</alias>
<!--proxool只能管理由自己产生的连接-->
<driver-url>
jdbc:oracle:thin:@192.168.0.244:1521:qdhw
</driver-url>
<driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
<driver-properties>
<property name="user" value="qdhw" />
<property name="password" value="qdhw" />
</driver-properties>
<!-- proxool自动侦察各个连接状态的时间间隔(毫秒),侦察到空闲的连接就马上回收,超时的销毁-->
<house-keeping-sleep-time>90000</house-keeping-sleep-time>
<!-- 指因未有空闲连接可以分配而在队列中等候的最大请求数,超过这个请求数的用户连接就不会被接受-->
<maximum-new-connections>30</maximum-new-connections>
<!-- 最少保持的空闲连接数-->
<prototype-count>5</prototype-count>
<!-- 允许最大连接数,超过了这个连接,再有请求时,就排在队列中等候,最大的等待请求数由maximum-new-connections决定-->
<maximum-connection-count>200</maximum-connection-count>
<!-- 最小连接数-->
<minimum-connection-count>10</minimum-connection-count>
</proxool>
</something-else-entirely>
第三步:加载并初始化proxool.xml文件。因为它是连接数据库的,其他很多模块都用到数据,所以你必须首先加载它,在web.xml中进行如下配置:如果你以前加载applicationContext.xml用的是:
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
这时你必须换成如下配置:
<servlet>
<servlet-name>contextConfigLocation</servlet-name>
<servlet-class>
org.springframework.web.context.ContextLoaderServlet
</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
要不然你就会遇见这样的错误:
Problem
org.logicalcobwebs.proxool.ProxoolException: Attempt to refer to a unregistered pool by its
alias 'dbPool'
如果用过proxool与spring整合时,不少就遇到过这样的问题,其实这个问题很明显就是你的proxool.xml没有被先加载初始化,我们应该让它先加载,应该这样配置:
<servlet>
<servlet-name>ServletConfigurator</servlet-name>
<servlet-class>
org.logicalcobwebs.proxool.configuration.ServletConfigurator
</servlet-class>
<init-param>
<param-name>xmlFile</param-name>
<param-value>WEB-INF/proxool.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
把<load-on-startup>的值设为1,值越小级别就越高,就先被加载初始化。一定要先于applicationContext.xml的加载。
第三步是参照网上的一些文章,试了许久,还是有错误,还是不行。几经折腾,在网上找到了解决的办法,就是自己写个监听器,用它来起动proxool连接池,然后在web.xml中配置一下,我的配置如下:
<!-- 配置proxool.xml连接池监听类 -->
<context-param>
<param-name>xmlFile</param-name>
<param-value>/WEB-INF/proxool.xml</param-value>
</context-param>
<listener>
<listener-class>com.xtlh.qdbridge.util.ProxoolListener</listener-class>
</listener>
监听器类如下:
import java.io.File;
import java.util.Enumeration;
import java.util.Properties;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.logicalcobwebs.proxool.ProxoolException;
import org.logicalcobwebs.proxool.configuration.JAXPConfigurator;
import org.logicalcobwebs.proxool.configuration.PropertyConfigurator;
public class ProxoolListener implements ServletContextListener
{
private static final Log LOG = LogFactory.getLog(ProxoolListener.class);
private static final String XML_FILE_PROPERTY = "xmlFile";
private static final String PROPERTY_FILE_PROPERTY = "propertyFile";
private static final String AUTO_SHUTDOWN_PROPERTY = "autoShutdown";
@SuppressWarnings("unused")
private boolean autoShutdown = true;
public void contextDestroyed(ServletContextEvent arg0){
System.out.println("destroy database pool....");
}
public void contextInitialized(ServletContextEvent contextEvent){
ServletContext context = contextEvent.getServletContext(); //对应servlet的init方法中ServletConfig.getServletContext()
String appDir = contextEvent.getServletContext().getRealPath("/");
Properties properties = new Properties();
Enumeration names = context.getInitParameterNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
String value = context.getInitParameter(name);
if (name.equals(XML_FILE_PROPERTY)) {
try {
File file = new File(value);
if (file.isAbsolute()) {
JAXPConfigurator.configure(value, false);
} else {
JAXPConfigurator.configure(appDir + File.separator + value, false);
}
} catch (ProxoolException e) {
LOG.error("Problem configuring " + value, e);
}
} else if (name.equals(PROPERTY_FILE_PROPERTY)) {
try {
File file = new File(value);
if (file.isAbsolute()) {
PropertyConfigurator.configure(value);
} else {
PropertyConfigurator.configure(appDir + File.separator + value);
}
} catch (ProxoolException e) {
LOG.error("Problem configuring " + value, e);
}
} else if (name.equals(AUTO_SHUTDOWN_PROPERTY)) {
autoShutdown = Boolean.valueOf(value).booleanValue();
} else if (name.startsWith("jdbc")) { //此处以前是PropertyConfigurator.PREFIX改为jdbc,因为此源码是0.9.1版本的,与0.9RC3版本有点不一样
properties.setProperty(name, value);
}
}
if (properties.size() > 0) {
try {
PropertyConfigurator.configure(properties);
} catch (ProxoolException e) {
LOG.error("Problem configuring using init properties", e);
}
}
}
}
最后一步:整合spring和proxool。在applicationContext.xml文件中把原来数据源的配置成这样:
<!-- 引入proxool.xml文件,proxool-0.9.1.jar包和proxool-cglib.jar -->
<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<!-- 将数据库连接交给了proxool管理,使它的驱动 -->
<value>org.logicalcobwebs.proxool.ProxoolDriver</value>
</property>
<property name="url">
<!-- 数据库连接池的别名,与你的proxool.xml中的Alias必须一致 -->
<value>proxool.dbPool</value>
</property>
</bean>
这样,就一切ok了。