P6Spy是记录JDBC调用日志信息的一个工具,既然记录了JDBC调用,当然就可以监听到SQL,是开发人员必备的开发利器.可以让开发人员非常方便的知道当前应用程序执行了那些sql
P6Spy官方网站http://www.p6spy.com/index.html
在介绍P6Spy工作原理之前先回忆下传统jdbc的取得连接的方法
Class.forName("oracle.jdbc.driver.OracleDriver");//动态加载oracle.jdbc.driver.OracleDriver类,有关类加载这里就不做介绍了.
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);//加载驱动后就可以取得连接了
多么经典的一段代码啊,通俗的说sun定义了一套jdbc接口,由各个数据库厂商去实现,其中java.sql.Driver是一个核心接口,该接口核心方法 boolean acceptsURL(String url) ,以OracleDriver为例,oracle.jdbc.driver.OracleDriver类实现了Driver接口,当显示的调用 Class.forName("oracle.jdbc.driver.OracleDriver");时,OracleDriver会被加载,执行static{}块内的代码,做些初始化工作.当然一个应用往往有时会连接多个数据库,所以衍生了DriverManager类,这个类负责管理多个数据库驱动,也就是多个driver对象,这也是为什么Driver接口有个方法叫acceptsURL的原因,因为当DriverManager管理多个driver对象的时候,调用DriverManager.getConnection(URL, USERNAME, PASSWORD);时,DriverManager必须知道当前Url请求的是那个数据库,最直接的实现想法就是循环遍历每个驱动调用驱动的acceptsURL方法,如果返回true的话,则返回该驱动的连接,所以每个数据库驱动定义的URL格式都不同,因为必须每个驱动都能识别多自己的URL. 同时DriverManager还提供registerDriver和deregisterDriver方法,前者将驱动实例添加到DriverManager类的容器中,后者将驱动从容器中删除,就是所谓的注册驱动和反注册驱动.
上面介绍了JDBC的基本工作原理,下面介绍下P6Spy的配置,首先要改驱动,例如把应用中写com.microsoft.jdbc.sqlserver.SQLServerDriver的地方改为com.p6spy.engine.spy.P6SpyDriver,无论是连接池还是经典的jdbc.然后在spy.properties驱动中配置realDriver,这里是真正的驱动com.microsoft.jdbc.sqlserver.SQLServerDriver,然后将p6spy.jar放到classpath中即可.至于其他输出形式的配置就不介绍了,例如sqlprofiler等.
了解了P6Spy的配置,下面来看P6Spy的源码,首先声明源码已经被我改过了,只保留了最最核心的东西,所以下面的源码和真实的P6Spy源码有些不同,但核心的方法和思想都是一样的,原来的方法中大量的辅助功能和配置参数判断,代码过长不便于贴出来分析. 由于本人文采不佳所以决定通过在代码上面添加注释的方式来讲解代码.
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.ResourceBundle;
public class P6SpyDriver extends P6SpyDriverCore {
static { // Class.forName("com.p6spy.engine.spy.P6SpyDriver");当加载这个类时会触发此程序块
init();
}
/**
* 初始化过程,本方法原名initMethod,由于父类也有此名称static方法不能重载为了避免引起奇异改为init
*/
public static void init() {
List driverNames = new ArrayList(); // 存放真实驱动的驱动名容器
try {
loadDriverNames(driverNames); // 从配置文件加载真实驱动的驱动名
if (driverNames == null || driverNames.size() == 0 )
return ;
P6SpyDriverCore.initMethod(driverNames); // 核心方法
} catch (Throwable e) {
e.printStackTrace();
}
}
private static void loadDriverNames(List driverNames) {
try {
ResourceBundle resources = ResourceBundle.getBundle( " spy-drivers " );
Enumeration keys = resources.getKeys();
while (keys.hasMoreElements()) {
driverNames.add(resources.getString(keys.nextElement()
.toString().trim()));
}
} catch (Throwable e) {
e.printStackTrace();
driverNames.add( " oracle.jdbc.driver.OracleDriver " );
driverNames.add( " com.microsoft.jdbc.sqlserver.SQLServerDriver " );
driverNames.add( " com.mysql.jdbc.Driver " );
driverNames.add( " COM.ibm.db2.jdbc.net.DB2Driver " );
driverNames.add( " com.informix.jdbc.IfxDriver " );
driverNames.add( " org.hsqldb.jdbcDriver " );
}
}
}