P6Spy使用: http://donald-draper.iteye.com/blog/2319646
P6Spy源码分析-属性文件加载: http://donald-draper.iteye.com/admin/blogs/2319851
使用P6Spy的时候用到这一句我们来看这一句的内涵:
P6DataSource p6DSource = new P6DataSource(cpDSource)
// p6DSource = new P6DataSource(cpDSource)
public class P6DataSource extends P6Base
implements DataSource, Referenceable, Serializable
{
//source是通过构造传入的数据源c3p0或Druid
public P6DataSource(DataSource source)
{
rds = source;
}
//初始化驱动及日志模块
public static void initMethod()
{
P6SpyDriverCore.initMethod((com.p6spy.engine.spy.P6SpyDriver.class).getName());
}
//获取Connection
public Connection getConnection()
throws SQLException
{
if(rds == null)
bindDataSource();
return P6SpyDriverCore.wrapConnection(rds.getConnection());
}
protected DataSource rds;
protected String rdsName;
//通过static语句块调用初始化方法
static
{
initMethod();
}
}
日志线路解析:
P6DataSource,的getConnection方法通过 P6SpyDriverCore.wrapConnection(rds.getConnection())获取连接;
再来看看P6SpyDriverCore的wrapConnection的方法都做了什么事情
public abstract class P6SpyDriverCore
implements Driver
{
public static synchronized void initMethod(String spydriver)
{
if(initialized)
return;
String path = P6SpyProperties.getPropertiesPath();
if(path == null)
{
foundSpyProperties = false;
return;
}
foundSpyProperties = true;
//初始化spy.properties属性文件
P6SpyProperties properties = new P6SpyProperties();
P6SpyOptions coreOptions = new P6SpyOptions();
OptionReloader.add(coreOptions, properties);
String className = "no class";
String classType = "driver";
try
{
//realdriver
ArrayList driverNames = null;
//日志模块
ArrayList modules = null;
//获取驱动名
driverNames = P6SpyOptions.allDriverNames();
//获取所有日志模块
modules = P6SpyOptions.allModules();
boolean hasModules = modules.size() > 0;
Iterator i = null;
classType = "driver";
Driver realDriver;
for(i = driverNames.iterator(); i.hasNext(); P6LogQuery.logDebug("Registered driver: " + className + ", realdriver: " + realDriver))
{
P6SpyDriver spy = null;
if(hasModules)
{
spy = new P6SpyDriver();
DriverManager.registerDriver(spy);
}
className = (String)i.next();
deregister(className);
realDriver = (Driver)P6Util.forName(className).newInstance();
if(P6SpyOptions.getDeregisterDrivers())
//注册驱动realdriver=com.mysql.jdbc.Driver
DriverManager.registerDriver(realDriver);
if(hasModules)
{
spy.setPassthru(realDriver);
realDrivers.add(realDriver);
}
}
if(hasModules)
{
factories = new ArrayList();
classType = "factory";
com.p6spy.engine.common.P6Options options;
for(i = modules.iterator(); i.hasNext(); P6LogQuery.logDebug("Registered factory: " + className + " with options: " + options))
{
className = (String)i.next();
//module.log=com.p6spy.engine.logging.P6LogFactory
//module.outage=com.p6spy.engine.outage.P6OutageFactory
P6Factory factory = (P6Factory)P6Util.forName(className).newInstance();
factories.add(factory);
options = factory.getOptions();
if(options != null)
OptionReloader.add(options, properties);
}
}
initialized = true;
for(Enumeration e = DriverManager.getDrivers(); e.hasMoreElements(); P6LogQuery.logDebug("Driver manager reporting driver registered: " + e.nextElement()));
}
catch(Exception e)
{
String err = "Error registering " + classType + " [" + className + "]\nCaused By: " + e.toString();
P6LogQuery.logError(err);
throw new P6DriverNotFoundError(err);
}
}
//P6DataSource的getConnection方法条用P6SpyDriverCore的wrapConnection(Connection realConnection)方法
public static Connection wrapConnection(Connection realConnection)
throws SQLException
{
Connection con = realConnection;
if(factories != null)
{
for(Iterator it = factories.iterator(); it.hasNext();)
{
P6Factory factory = (P6Factory)it.next();
//这里是重点,这里是通过P6Factory来获取连接,P6SpyDriverCore
//在初始化initMethod已经P6LogFactory,P6OutageFactory
//module.log=com.p6spy.engine.logging.P6LogFactory
//module.outage=com.p6spy.engine.outage.P6OutageFactory
con = factory.getConnection(con);
}
}
return con;
}
protected Driver passthru;
protected static boolean initialized = false;
protected static ArrayList factories;
protected static ArrayList realDrivers = new ArrayList();
protected static boolean foundSpyProperties;
}
这一句很重要:con = factory.getConnection(con),这个factory实际上是P6LogFactory或P6OutageFactory
再来看看P6LogFactory的getConnection()的方法
public class P6LogFactory extends P6CoreFactory
{
//返回的是P6LogConnection
public Connection getConnection(Connection conn)
throws SQLException
{
return new P6LogConnection(this, conn);
}
//返回的是P6LogPreparedStatement
public PreparedStatement getPreparedStatement(PreparedStatement real, P6Connection conn, String p0)
throws SQLException
{
return new P6LogPreparedStatement(this, real, conn, p0);
}
}
再来看看P6LogConnection实现了Connection同时继承了P6Connection
public class P6LogConnection extends P6Connection
implements Connection
{
public P6LogConnection(P6Factory factory, Connection conn)
throws SQLException
{
super(factory, conn);
}
//事务提交
public void commit()
throws SQLException
{
long startTime = System.currentTimeMillis();
try
{
passthru.commit();
}
finally
{
P6LogQuery.logElapsed(getId(), startTime, "commit", "", "");
}
}
//事务回滚
public void rollback()
throws SQLException
{
long startTime = System.currentTimeMillis();
try
{
passthru.rollback();
}
finally
{
P6LogQuery.logElapsed(getId(), startTime, "rollback", "", "");
}
}
//回滚的指定点
public void rollback(Savepoint p0)
throws SQLException
{
long startTime = System.currentTimeMillis();
try
{
passthru.rollback(p0);
}
finally
{
P6LogQuery.logElapsed(getId(), startTime, "rollback", "", "");
}
}
}
再看P6Connection
public class P6Connection extends P6Base
implements Connection
{
获取预编译Statement,看到这是不是很熟悉的JDBC的Connection.prepareStatement(String sql)
public PreparedStatement prepareStatement(String p0)
throws SQLException
{
这里条用的实际就是P6LogFactory的getPreparedStatement的方法
return getP6Factory().getPreparedStatement(passthru.prepareStatement(p0), this, p0);
}
}
再看P6LogFactory的getPreparedStatement方法
public class P6LogFactory extends P6CoreFactory
{
//返回的是P6LogPreparedStatement
public PreparedStatement getPreparedStatement(PreparedStatement real, P6Connection conn, String p0)
throws SQLException
{
return new P6LogPreparedStatement(this, real, conn, p0);
}
}
再看P6LogPreparedStatement
public class P6LogPreparedStatement extends P6PreparedStatement
implements PreparedStatement
{
public P6LogPreparedStatement(P6Factory factory, PreparedStatement statement, P6Connection conn, String query)
{
super(factory, statement, conn, query);
}
//插入
public boolean execute()
throws SQLException
{
long startTime = System.currentTimeMillis();
boolean flag;
try
{
flag = prepStmtPassthru.execute();
}
finally
{
//打印日志
P6LogQuery.logElapsed(connection.getId(), startTime, "statement", preparedQuery, getQueryFromPreparedStatement());
}
return flag;
}
//查询
public ResultSet executeQuery()
throws SQLException
{
long startTime = System.currentTimeMillis();
ResultSet resultset;
try
{
resultset = getP6Factory().getResultSet(prepStmtPassthru.executeQuery(), this, preparedQuery, getQueryFromPreparedStatement());
}
finally
{
//打印日志
P6LogQuery.logElapsed(connection.getId(), startTime, "statement", preparedQuery, getQueryFromPreparedStatement());
}
return resultset;
}
//更新
public int executeUpdate()
throws SQLException
{
long startTime = System.currentTimeMillis();
int i;
try
{
i = prepStmtPassthru.executeUpdate();
}
finally
{
//打印日志
P6LogQuery.logElapsed(connection.getId(), startTime, "statement", preparedQuery, getQueryFromPreparedStatement());
}
return i;
}
日志打印类P6LogQuery:
public class P6LogQuery
{
public static synchronized void initMethod()
{
//日志appender信息
String appender = P6SpyOptions.getAppender();
if(appender == null)
appender = "com.p6spy.engine.logging.appender.FileLogger";
try
{
logger = (P6Logger)P6Util.forName(appender).newInstance();
}
catch(Exception e1)
{
try
{
ClassLoader loader = ClassLoader.getSystemClassLoader();
logger = (P6Logger)loader.loadClass(appender).newInstance();
}
catch(Exception e)
{
System.err.println("Cannot instantiate " + appender + ", even on second attempt. Logging to file log4jaux.log: " + e);
}
}
if(logger != null && (logger instanceof FileLogger))
{
String logfile = P6SpyOptions.getLogfile();
logfile = logfile != null ? logfile : "spy.log";
((FileLogger)logger).setLogfile(logfile);
}
if(P6SpyOptions.getFilter())
{
includeTables = parseCSVList(P6SpyOptions.getInclude());
excludeTables = parseCSVList(P6SpyOptions.getExclude());
}
includeCategories = parseCSVList(P6SpyOptions.getIncludecategories());
excludeCategories = parseCSVList(P6SpyOptions.getExcludecategories());
}
//打印log
public static void logElapsed(int connectionId, long startTime, String category, String prepared, String sql)
{
logElapsed(connectionId, startTime, System.currentTimeMillis(), category, prepared, sql);
}
public static void logElapsed(int connectionId, long startTime, long endTime, String category, String prepared, String sql)
{
if(logger != null && meetsThresholdRequirement(endTime - startTime) && isLoggable(sql) && isCategoryOk(category))
doLogElapsed(connectionId, startTime, endTime, category, prepared, sql);
else
if(isDebugOn())
logDebug("P6Spy intentionally did not log category: " + category + ", statement: " + sql + " Reason: logger=" + logger + ", isLoggable=" + isLoggable(sql) + ", isCategoryOk=" + isCategoryOk(category));
}
protected static void doLogElapsed(int connectionId, long startTime, long endTime, String category, String prepared, String sql)
{
doLog(connectionId, endTime - startTime, category, prepared, sql);
}
//打印log
protected static synchronized void doLog(int connectionId, long elapsed, String category, String prepared, String sql)
{
if(logger != null)
{
Date now = P6Util.timeNow();
SimpleDateFormat sdf = P6SpyOptions.getDateformatter();
String stringNow;
if(sdf == null)
stringNow = Long.toString(now.getTime());
else
stringNow = sdf.format(new Date(now.getTime())).trim();
logger.logSQL(connectionId, stringNow, elapsed, category, prepared, sql);
boolean stackTrace = P6SpyOptions.getStackTrace();
String stackTraceClass = P6SpyOptions.getStackTraceClass();
if(stackTrace)
{
Exception e = new Exception();
if(stackTraceClass != null)
{
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
String stack = sw.toString();
if(stack.indexOf(stackTraceClass) != -1)
lastStack = stack;
else
e = null;
}
if(e != null)
logger.logException(e);
}
}
}
public static void logInfo(String sql)
{
if(logger != null && isCategoryOk("info"))
doLog(-1L, "info", "", sql);
}
public static boolean isDebugOn()
{
return isCategoryOk("debug");
}
public static void logDebug(String sql)
{
if(isDebugOn())
if(logger != null)
doLog(-1L, "debug", "", sql);
else
System.err.println(sql);
}
public static void logError(String sql)
{
System.err.println("Warning: " + sql);
if(logger != null)
doLog(-1L, "error", "", sql);
}
protected static PrintStream qlog;
protected static String includeTables[];
protected static String excludeTables[];
protected static String includeCategories[];
protected static String excludeCategories[];
protected static String lastStack;
//log打印类
protected static P6Logger logger;
//通过静态语句块调用出事化方法
static
{
initMethod();
}
}
P6Logger类:
public interface P6Logger
{
public abstract void logSQL(int i, String s, long l, String s1, String s2, String s3);
public abstract void logException(Exception exception);
public abstract void logText(String s);
public abstract String getLastEntry();
}
P6Logger实现类:
log4j日志
public class Log4jLogger extends FormattedLogger
implements P6Logger
{
public Log4jLogger()
{
level = Level.INFO;
P6SpyProperties properties = new P6SpyProperties();
PropertyConfigurator.configure(properties.forceReadProperties());
log = Logger.getLogger("p6spy");
log.setAdditivity(false);
}
public void logException(Exception e)
{
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
logText(sw.toString());
}
public void logText(String text)
{
log.log(level, text);
setLastEntry(text);
}
public Level getLevel()
{
return level;
}
public void setLevel(Level inVar)
{
level = inVar;
}
protected Level level;
protected String lastEntry;
private static Logger log;
}
标准控制输出
public class StdoutLogger extends FormattedLogger
implements P6Logger
{
public StdoutLogger()
{
qlog = System.out;
}
public void logException(Exception e)
{
e.printStackTrace(qlog);
}
public void logText(String text)
{
qlog.println(text);
setLastEntry(text);
}
protected PrintStream qlog;
}
FormattedLogger类
public abstract class FormattedLogger
{
public FormattedLogger()
{
}
//日志打印
public void logSQL(int connectionId, String now, long elapsed, String category, String prepared, String sql)
{
String logEntry = now + "|" + elapsed + "|" + (connectionId != -1 ? String.valueOf(connectionId) : "") + "|" + category + "|" + prepared + "|" + sql;
logText(logEntry);
}
public abstract void logText(String s);
public void setLastEntry(String inVar)
{
lastEntry = inVar;
}
public String getLastEntry()
{
return lastEntry;
}
protected String lastEntry;
}
总结:
通过以上的分析,相信大家对P6Spy如何属性配置,connection获取,日志打印有了初步的了解,主要点是利用static语句块,初始化属性,利用工场模式获取connection,日志的打印主要通过封装实现jdbc的statement来嵌入。