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来嵌入。