对一个对象进行装饰那叫装饰器模式,对一群对象装饰叫门面模式
今天为了在打印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; } }
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)); } }
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; } }
以上用了三个装饰器,对数据库驱动进去了扩展,使之每一次设置到?的值都会被一个数组接收,,,,,,