下面把参考文章附上:
今天为了在打印sql日志时,能够打印出完整的sql日志(不带‘?’),测试了下 p6spy ,可以满足需求,查看了下里面的大致的源码,主要采用了装饰器模式进行扩展的。在此做下笔记。
1,p6spy的配置在网络上google下。
2,Class.forName("com.p6spy.engine.spy.P6SpyDriver");进行触发该类下静态模块的执行,
---》这个主要实现了该类下的initMethod P6SpyDriver extends P6SpyDriverCore
- public abstract class P6SpyDriverCore implements Driver {
- //由实现的接口,以及该声明,就可知其为decorator
- protected Driver passthru = null;
- public synchronized static void initMethod(String spydriver) {
- //主要实现为两步,1,对DrvierManager的扩展,2,connect的获取
- //这里只粘出重点的代码
- if (hasModules) {
- spy = new P6SpyDriver();
- //注册进DriverManager,你如果在写连接时不用Class.forName()的话,也可以用这种设置
- DriverManager.registerDriver(spy);
- }
- //在配置文件里,读取真的driver
- Driver realDriver = (Driver)P6Util.forName(className).newInstance();
- if (P6SpyOptions.getDeregisterDrivers()) {
- // just in case you had to deregister
- DriverManager.registerDriver(realDriver);
- }
- // now wrap your realDriver in the spy
- if (hasModules) {
- //设置到以上的参数中
- spy.setPassthru(realDriver);
- realDrivers.add(realDriver);
- }
- }
- public Connection connect(String p0, java.util.Properties p1) throws SQLException {
- Connection conn = passthru.connect(realUrl,p1);
- if (conn != null) {
- //这里是对connection的包装,也是一个decorator //P6LogConnection implements Connection
- //供DriverManager.getConnection()获取,
- conn = wrapConnection(conn);
- }
- return conn;
- }
- }
public abstract class P6SpyDriverCore implements Driver {
//由实现的接口,以及该声明,就可知其为decorator
protected Driver passthru = null;
public synchronized static void initMethod(String spydriver) {
//主要实现为两步,1,对DrvierManager的扩展,2,connect的获取
//这里只粘出重点的代码
if (hasModules) {
spy = new P6SpyDriver();
//注册进DriverManager,你如果在写连接时不用Class.forName()的话,也可以用这种设置
DriverManager.registerDriver(spy);
}
//在配置文件里,读取真的driver
Driver realDriver = (Driver)P6Util.forName(className).newInstance();
if (P6SpyOptions.getDeregisterDrivers()) {
// just in case you had to deregister
DriverManager.registerDriver(realDriver);
}
// now wrap your realDriver in the spy
if (hasModules) {
//设置到以上的参数中
spy.setPassthru(realDriver);
realDrivers.add(realDriver);
}
}
public Connection connect(String p0, java.util.Properties p1) throws SQLException {
Connection conn = passthru.connect(realUrl,p1);
if (conn != null) {
//这里是对connection的包装,也是一个decorator //P6LogConnection implements Connection
//供DriverManager.getConnection()获取,
conn = wrapConnection(conn);
}
return conn;
}
}
3,当DriverManager.getConnection(...)时,就会去调用以上的connect而这个connect也是经过包装的。。
- //现在到了P6Connection.prepareStatement(sql);
- public class P6Connection extends P6Base implements java.sql.Connection {
- protected Connection passthru;
- //P6PreparedStatement 返回的也是对PreparedStatement的装饰扩展
- public PreparedStatement prepareStatement(String p0) throws SQLException {
- return (getP6Factory().getPreparedStatement(passthru.prepareStatement(p0), this, p0));
- }
- }
//现在到了P6Connection.prepareStatement(sql);
public class P6Connection extends P6Base implements java.sql.Connection {
protected Connection passthru;
//P6PreparedStatement 返回的也是对PreparedStatement的装饰扩展
public PreparedStatement prepareStatement(String p0) throws SQLException {
return (getP6Factory().getPreparedStatement(passthru.prepareStatement(p0), this, p0));
}
}
4,这一步到了处理PreparedStatement,以上的扩展为的就是为了驱动时执行我们所装饰的P6PreparedStatement
- public class P6PreparedStatement extends P6Statement implements PreparedStatement {
- public final static int P6_MAX_FIELDS = 32;
- public static int P6_GROW_MAX = 32;
- protected PreparedStatement prepStmtPassthru;
- protected String preparedQuery;
- protected Object values[];//扩展就是为了取我们所设置的值
- protected boolean isString[];
- public P6PreparedStatement(P6Factory factory, PreparedStatement statement, P6Connection conn, String query) {
- super(factory, statement, conn);
- prepStmtPassthru = statement;
- this.preparedQuery = query;
- initValues();
- }
- protected void initValues() {
- values = new Object[P6_MAX_FIELDS+1];
- isString = new boolean[P6_MAX_FIELDS+1];
- }
- public void addBatch() throws SQLException {
- prepStmtPassthru.addBatch();
- }
- public void clearParameters() throws SQLException {
- prepStmtPassthru.clearParameters();
- }
- public boolean execute() throws SQLException {
- return prepStmtPassthru.execute();
- }
- public ResultSet executeQuery() throws SQLException {
- ResultSet resultSet = prepStmtPassthru.executeQuery();
- return (getP6Factory().getResultSet(resultSet, this, preparedQuery, getQueryFromPreparedStatement()));
- }
- public int executeUpdate() throws SQLException {
- return prepStmtPassthru.executeUpdate();
- }
- public ResultSetMetaData getMetaData() throws SQLException {
- return prepStmtPassthru.getMetaData();
- }
- public void setArray(int p0, Array p1) throws SQLException {
- setObjectAsString(p0, p1);
- // we need to make sure we get the real object in this case
- if (p1 instanceof P6Array) {
- prepStmtPassthru.setArray(p0,((P6Array)p1).passthru);
- } else{
- prepStmtPassthru.setArray(p0,p1);
- }
- }
- //以下设置都为装饰器的扩展,使我们每一次设置到?的值都会加到数组中去。
- public void setAsciiStream(int p0, InputStream p1, int p2) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setAsciiStream(p0,p1,p2);
- }
- public void setBigDecimal(int p0, BigDecimal p1) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setBigDecimal(p0,p1);
- }
- public void setBinaryStream(int p0, InputStream p1, int p2) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setBinaryStream(p0,p1,p2);
- }
- public void setBlob(int p0, Blob p1) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setBlob(p0,p1);
- }
- public void setBoolean(int p0, boolean p1) throws SQLException {
- setObjectAsString(p0, new Boolean(p1));
- prepStmtPassthru.setBoolean(p0,p1);
- }
- public void setByte(int p0, byte p1) throws SQLException {
- setObjectAsString(p0, new Byte(p1));
- prepStmtPassthru.setByte(p0,p1);
- }
- public void setBytes(int p0, byte[] p1) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setBytes(p0,p1);
- }
- public void setCharacterStream(int p0, Reader p1, int p2) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setCharacterStream(p0,p1,p2);
- }
- public void setClob(int p0, Clob p1) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setClob(p0,p1);
- }
- public void setDate(int p0, Date p1) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setDate(p0,p1);
- }
- public void setDate(int p0, Date p1, java.util.Calendar p2) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setDate(p0,p1,p2);
- }
- public void setDouble(int p0, double p1) throws SQLException {
- setObjectAsInt(p0, new Double(p1));
- prepStmtPassthru.setDouble(p0,p1);
- }
- public void setFloat(int p0, float p1) throws SQLException {
- setObjectAsInt(p0, new Float(p1));
- prepStmtPassthru.setFloat(p0,p1);
- }
- public void setInt(int p0, int p1) throws SQLException {
- setObjectAsInt(p0, new Integer(p1));
- prepStmtPassthru.setInt(p0,p1);
- }
- public void setLong(int p0, long p1) throws SQLException {
- setObjectAsInt(p0, new Long(p1));
- prepStmtPassthru.setLong(p0,p1);
- }
- public void setNull(int p0, int p1, String p2) throws SQLException {
- setObjectAsString(p0, null);
- prepStmtPassthru.setNull(p0,p1,p2);
- }
- public void setNull(int p0, int p1) throws SQLException {
- setObjectAsString(p0, null);
- prepStmtPassthru.setNull(p0,p1);
- }
- public void setObject(int p0, Object p1, int p2, int p3) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setObject(p0,p1,p2,p3);
- }
- public void setObject(int p0, Object p1, int p2) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setObject(p0,p1,p2);
- }
- public void setObject(int p0, Object p1) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setObject(p0,p1);
- }
- public void setRef(int p0, Ref p1) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setRef(p0,p1);
- }
- public void setShort(int p0, short p1) throws SQLException {
- setObjectAsString(p0, new Short(p1));
- prepStmtPassthru.setShort(p0,p1);
- }
- public void setString(int p0, String p1) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setString(p0,p1);
- }
- public void setTime(int p0, Time p1, java.util.Calendar p2) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setTime(p0,p1,p2);
- }
- public void setTime(int p0, Time p1) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setTime(p0,p1);
- }
- public void setTimestamp(int p0, Timestamp p1, java.util.Calendar p2) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setTimestamp(p0,p1,p2);
- }
- public void setTimestamp(int p0, Timestamp p1) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setTimestamp(p0,p1);
- }
- public void setUnicodeStream(int p0, InputStream p1, int p2) throws SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setUnicodeStream(p0,p1,p2);
- }
- /* we override this because the p6statement version will not be
- * able to return the accurate prepared statement or query information
- */
- // bug 161: getResultSet() should return null if this is an update
- // count or there are not more result sets
- public java.sql.ResultSet getResultSet() throws java.sql.SQLException {
- ResultSet rs = passthru.getResultSet();
- return (rs == null) ? null : getP6Factory().getResultSet(rs, this, preparedQuery, getQueryFromPreparedStatement());
- }
- /*
- * P6Spy specific functionality
- */
- //这一步是对数组与sql进行处理,输出完整的sql语句
- public final String getQueryFromPreparedStatement() {
- int len = preparedQuery.length();
- StringBuffer t = new StringBuffer(len * 2);
- if (values != null) {
- int i = 1, limit = 0, base = 0;
- while ((limit = preparedQuery.indexOf('?',limit)) != -1) {
- if (isString[i]) {
- t.append(preparedQuery.substring(base,limit));
- t.append("'");
- t.append(values[i]);
- t.append("'");
- } else {
- t.append(preparedQuery.substring(base,limit));
- t.append(values[i]);
- }
- i++;
- limit++;
- base = limit;
- }
- if (base < len) {
- t.append(preparedQuery.substring(base));
- }
- }
- return t.toString();
- }
- protected void growValues(int newMax) {
- int size = values.length;
- Object [] values_tmp = new Object[newMax + P6_GROW_MAX];
- boolean [] isString_tmp = new boolean[newMax + P6_GROW_MAX];
- System.arraycopy(values, 0, values_tmp, 0, size);
- values = values_tmp;
- System.arraycopy(isString, 0, isString_tmp, 0, size);
- isString = isString_tmp;
- }
- protected void setObjectAsString(int i, Object o) {
- if (values != null) {
- if (i >= 0) {
- if ( i >= values.length) {
- growValues(i);
- }
- values[i] = (o == null) ? "" : o.toString();
- isString[i] = true;
- }
- }
- }
- protected void setObjectAsInt(int i, Object o) {
- if (values != null) {
- if (i >=0) {
- if (i >= values.length) {
- growValues(i);
- }
- values[i] = (o == null) ? "" : o.toString();
- isString[i] = false;
- }
- }
- }
- // Since JDK 1.4
- public void setURL(int p0, java.net.URL p1) throws java.sql.SQLException {
- setObjectAsString(p0, p1);
- prepStmtPassthru.setURL(p0, p1);
- }
- // Since JDK 1.4
- public java.sql.ParameterMetaData getParameterMetaData() throws java.sql.SQLException {
- return(prepStmtPassthru.getParameterMetaData());
- }
- /**
- * Returns the underlying JDBC object (in this case, a
- * java.sql.PreparedStatement).
- * <p>
- * The returned object is a java.sql.Statement due
- * to inheritance reasons, so you'll need to cast
- * appropriately.
- *
- * @return the wrapped JDBC object
- */
- public Statement getJDBC() {
- Statement wrapped = (prepStmtPassthru instanceof P6Statement) ?
- ((P6Statement) prepStmtPassthru).getJDBC() :
- prepStmtPassthru;
- return wrapped;
- }
- public int getValuesLength() {
- return values.length;
- }
- }
public class P6PreparedStatement extends P6Statement implements PreparedStatement {
public final static int P6_MAX_FIELDS = 32;
public static int P6_GROW_MAX = 32;
protected PreparedStatement prepStmtPassthru;
protected String preparedQuery;
protected Object values[];//扩展就是为了取我们所设置的值
protected boolean isString[];
public P6PreparedStatement(P6Factory factory, PreparedStatement statement, P6Connection conn, String query) {
super(factory, statement, conn);
prepStmtPassthru = statement;
this.preparedQuery = query;
initValues();
}
protected void initValues() {
values = new Object[P6_MAX_FIELDS+1];
isString = new boolean[P6_MAX_FIELDS+1];
}
public void addBatch() throws SQLException {
prepStmtPassthru.addBatch();
}
public void clearParameters() throws SQLException {
prepStmtPassthru.clearParameters();
}
public boolean execute() throws SQLException {
return prepStmtPassthru.execute();
}
public ResultSet executeQuery() throws SQLException {
ResultSet resultSet = prepStmtPassthru.executeQuery();
return (getP6Factory().getResultSet(resultSet, this, preparedQuery, getQueryFromPreparedStatement()));
}
public int executeUpdate() throws SQLException {
return prepStmtPassthru.executeUpdate();
}
public ResultSetMetaData getMetaData() throws SQLException {
return prepStmtPassthru.getMetaData();
}
public void setArray(int p0, Array p1) throws SQLException {
setObjectAsString(p0, p1);
// we need to make sure we get the real object in this case
if (p1 instanceof P6Array) {
prepStmtPassthru.setArray(p0,((P6Array)p1).passthru);
} else{
prepStmtPassthru.setArray(p0,p1);
}
}
//以下设置都为装饰器的扩展,使我们每一次设置到?的值都会加到数组中去。
public void setAsciiStream(int p0, InputStream p1, int p2) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setAsciiStream(p0,p1,p2);
}
public void setBigDecimal(int p0, BigDecimal p1) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setBigDecimal(p0,p1);
}
public void setBinaryStream(int p0, InputStream p1, int p2) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setBinaryStream(p0,p1,p2);
}
public void setBlob(int p0, Blob p1) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setBlob(p0,p1);
}
public void setBoolean(int p0, boolean p1) throws SQLException {
setObjectAsString(p0, new Boolean(p1));
prepStmtPassthru.setBoolean(p0,p1);
}
public void setByte(int p0, byte p1) throws SQLException {
setObjectAsString(p0, new Byte(p1));
prepStmtPassthru.setByte(p0,p1);
}
public void setBytes(int p0, byte[] p1) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setBytes(p0,p1);
}
public void setCharacterStream(int p0, Reader p1, int p2) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setCharacterStream(p0,p1,p2);
}
public void setClob(int p0, Clob p1) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setClob(p0,p1);
}
public void setDate(int p0, Date p1) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setDate(p0,p1);
}
public void setDate(int p0, Date p1, java.util.Calendar p2) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setDate(p0,p1,p2);
}
public void setDouble(int p0, double p1) throws SQLException {
setObjectAsInt(p0, new Double(p1));
prepStmtPassthru.setDouble(p0,p1);
}
public void setFloat(int p0, float p1) throws SQLException {
setObjectAsInt(p0, new Float(p1));
prepStmtPassthru.setFloat(p0,p1);
}
public void setInt(int p0, int p1) throws SQLException {
setObjectAsInt(p0, new Integer(p1));
prepStmtPassthru.setInt(p0,p1);
}
public void setLong(int p0, long p1) throws SQLException {
setObjectAsInt(p0, new Long(p1));
prepStmtPassthru.setLong(p0,p1);
}
public void setNull(int p0, int p1, String p2) throws SQLException {
setObjectAsString(p0, null);
prepStmtPassthru.setNull(p0,p1,p2);
}
public void setNull(int p0, int p1) throws SQLException {
setObjectAsString(p0, null);
prepStmtPassthru.setNull(p0,p1);
}
public void setObject(int p0, Object p1, int p2, int p3) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setObject(p0,p1,p2,p3);
}
public void setObject(int p0, Object p1, int p2) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setObject(p0,p1,p2);
}
public void setObject(int p0, Object p1) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setObject(p0,p1);
}
public void setRef(int p0, Ref p1) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setRef(p0,p1);
}
public void setShort(int p0, short p1) throws SQLException {
setObjectAsString(p0, new Short(p1));
prepStmtPassthru.setShort(p0,p1);
}
public void setString(int p0, String p1) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setString(p0,p1);
}
public void setTime(int p0, Time p1, java.util.Calendar p2) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setTime(p0,p1,p2);
}
public void setTime(int p0, Time p1) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setTime(p0,p1);
}
public void setTimestamp(int p0, Timestamp p1, java.util.Calendar p2) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setTimestamp(p0,p1,p2);
}
public void setTimestamp(int p0, Timestamp p1) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setTimestamp(p0,p1);
}
public void setUnicodeStream(int p0, InputStream p1, int p2) throws SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setUnicodeStream(p0,p1,p2);
}
/* we override this because the p6statement version will not be
* able to return the accurate prepared statement or query information
*/
// bug 161: getResultSet() should return null if this is an update
// count or there are not more result sets
public java.sql.ResultSet getResultSet() throws java.sql.SQLException {
ResultSet rs = passthru.getResultSet();
return (rs == null) ? null : getP6Factory().getResultSet(rs, this, preparedQuery, getQueryFromPreparedStatement());
}
/*
* P6Spy specific functionality
*/
//这一步是对数组与sql进行处理,输出完整的sql语句
public final String getQueryFromPreparedStatement() {
int len = preparedQuery.length();
StringBuffer t = new StringBuffer(len * 2);
if (values != null) {
int i = 1, limit = 0, base = 0;
while ((limit = preparedQuery.indexOf('?',limit)) != -1) {
if (isString[i]) {
t.append(preparedQuery.substring(base,limit));
t.append("'");
t.append(values[i]);
t.append("'");
} else {
t.append(preparedQuery.substring(base,limit));
t.append(values[i]);
}
i++;
limit++;
base = limit;
}
if (base < len) {
t.append(preparedQuery.substring(base));
}
}
return t.toString();
}
protected void growValues(int newMax) {
int size = values.length;
Object [] values_tmp = new Object[newMax + P6_GROW_MAX];
boolean [] isString_tmp = new boolean[newMax + P6_GROW_MAX];
System.arraycopy(values, 0, values_tmp, 0, size);
values = values_tmp;
System.arraycopy(isString, 0, isString_tmp, 0, size);
isString = isString_tmp;
}
protected void setObjectAsString(int i, Object o) {
if (values != null) {
if (i >= 0) {
if ( i >= values.length) {
growValues(i);
}
values[i] = (o == null) ? "" : o.toString();
isString[i] = true;
}
}
}
protected void setObjectAsInt(int i, Object o) {
if (values != null) {
if (i >=0) {
if (i >= values.length) {
growValues(i);
}
values[i] = (o == null) ? "" : o.toString();
isString[i] = false;
}
}
}
// Since JDK 1.4
public void setURL(int p0, java.net.URL p1) throws java.sql.SQLException {
setObjectAsString(p0, p1);
prepStmtPassthru.setURL(p0, p1);
}
// Since JDK 1.4
public java.sql.ParameterMetaData getParameterMetaData() throws java.sql.SQLException {
return(prepStmtPassthru.getParameterMetaData());
}
/**
* Returns the underlying JDBC object (in this case, a
* java.sql.PreparedStatement).
* <p>
* The returned object is a java.sql.Statement due
* to inheritance reasons, so you'll need to cast
* appropriately.
*
* @return the wrapped JDBC object
*/
public Statement getJDBC() {
Statement wrapped = (prepStmtPassthru instanceof P6Statement) ?
((P6Statement) prepStmtPassthru).getJDBC() :
prepStmtPassthru;
return wrapped;
}
public int getValuesLength() {
return values.length;
}
}
以上用了三个装饰器,对数据库驱动进去了扩展,使之每一次设置到?的值都会被一个数组接收,,,,,,