flect.Proxy 对象是对class 文件的调用起到一个代理作用。对于目的class 中的每个方法的调用首先都要经过proxy 的处理方法。然后在 proxy 的处理方法(invoke 方法)里面才真正的开始调用目的class 里面的方法。
例如:
Test t = new Test();
t.print(null)
在没有使用代理的情况下,这里的print 方法的调用应该是直接到Test 类里面调用这个方法了。
这里当把Test 类绑定到InvocationHandler 对象(类)的时候。也就是把这个Test 类出卖给了Proxy,这样如果要是再想调用Test 类里面的方法就要通过Proxy 的处理方法invoke(实现InvocationHandler 接口的)了。有那里调用。简单的说“被了”
下面我们就来通过这个特性来做一个数据库操作的日志记录过滤器。
在我们程序运行中,数据库调用阶段的日志对我们分析程序的错误很有参考价值。这里我们就做一个代理的过滤器,用于记录对数据库的读取,更新等一系列操作的接口日志的详细记录的过滤程序。用于记录调
用数据库执行的SQL ,SQL 的参数等。可谓意义还是有点的啦,这里老孙经过一天的调试整理,捣鼓的程序供大家参考。本文为参看ibatis 源代码。网上有人说这玩意就是AOP,我才不管它是啥 P 呢,能满足我的要求便可。
这里我们创建  5 个java 文件
BaseProxy.java 代理实现基类
ConnectionProxy.java 用于记录调用connection 对象的时候记录日志。PreparedStatementProxy.java 用于记录PreparedStatem ent 对象的方法调用过程的日志记录ResultSetProxy.java 用于记录ResultSet 对象方法调用的时候的日志。
StatementProxy.java 用于记录Statem ent 对象方法调用时候的日志。
这里开始铺设源代码
BaseProxy.java 这个文件是基础类,用于存放一些公共的参数,方法名称,还有调用SQL
的时候我们最关注的绑定变量的参数。
package net.chinacsharp.proxy;
import java.util.ArrayLis t;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class BaseProxy {
/**
* 存放statement 对象的 set 方法。
*/
protected static final Set setMethods = new HashSet();
/
**
* 存放statement 对象的 get 方法。
*/
protected static final Set getMethods = new HashSet();
/**
* 存放statement 对象的 exec 的几个方法。
*/
protected static final Set execSqlMethods = new HashSet();private Map paramsMap = new HashMap();
private List paramsNames = new ArrayList();
private List paramsValues = new ArrayList();
/**
* 初始id,用于确定Proxy 的同一个对象
*/
private static int nextId = 100000;
/**
* 用于确定Proxy 的同一个对象
*/
protected int id;
static {
setMethods.add("setString");
setMethods.add("setInt");
setMethods.add("setByte");
setMethods.ad d("setShort");
setMethods.add("setLong");
setMethods.add("setDouble");
setMethods.add("setFloat");
setMethods.add("setTimestamp");
setMethods.add("setDate");
setMethods.add("setTime");
setMethods.add("setArray");
setMethods.add("setBigDecimal");
setMethods.add("setAsciiStream");
setMethods.add("setBinaryStream");
setMethods.add("setBlob");
setMethods.add("setBoolean");
setMethods.add("setBytes");
setMethods.add("setCharacterStream");
setMethods.add("setClob");
setMethods.add("setObject");
setMethods.add("se tNull");
getMethods.add("getString");
getMethods.add("getInt");
getMethods.add("getByte");
getMethods.add("getShort");
getMethods.add("getLong");
getMethods.add("getDouble");
getMethods.add("getFloat");
getMethods.add("getTimestamp");
getMethods.add("getDa te");
getMethods.add("getTime");
getMethods.add("getArray");
getMethods.add("getBigDecimal");
getMethods.add("getAsciiStream");
getMethods.add("getBinaryStream");
getMethods.add("getBlob");
getMethods.add("getBoolean");
getMethods.add("getBytes");
getMetho ds.add("getCharacterStream");
getMethods.add("getClob");
getMethods.add("getObject");
getMethods.add("getNull");
execSqlMethods.add("execute");
execSqlMethods.add("executeUpdate");
execSqlMethods.add("executeQuery");
}
public BaseProxy() {
id = getNextId();
}
/**
* 用于取得proxy 调用对象的id,这里防止id 重复,所以是同步的* @return
*/
protected synchronized static int getNextId() {
return nextId++;
}
protected void setColumn(Object key, Object value) { paramsMap.put(key, value);
paramsNames.add(key);
paramsValu es.add(value);
}
protected Object getColumn(Object key) {
(key);
}
protected String getV alueString() {
String();
}
protected String getTypeString() {
List typeList = new ArrayList(paramsValues.size());
for (int i = 0; i < paramsValues.size(); i++) {
Object value = (i);
if (value == null) {
typeList.add("null");
} else {
typeList.Class().getName());
}
}
String();
}
protected String getColumnString() {
String();
}
protected void clearColumnInfo() {
paramsMap.clear();
paramsNames.clear();
paramsValues.clear();
}
}
ConnectionProxy.java 这个类把connection 方法装到了 proxy 代理过滤文件列表里面。这里
调用conncetion 的无论哪个方法,其实都要先通过ConnectionProxy 类的invoke 方法,我们
在invoke 方法这里记录下调用的日志情况:
package net.chinacsharp.proxy;
import flect.InvocationHandler;
import flect.Method;
import flect.Proxy;
import java.sql.Connection;
import java.sql.PreparedStatement;
springboot实现aop
import java.sql.Statement;
import org.apachemons.logging.Log;
import org.apachemons.logging.LogFactory;
/**
* 本类用于记录Connection 一层的日志
*/
public class ConnectionProxy extends BaseProxy implements InvocationHandler { private static final Log log = Log(ConnectionProxy.class);
private Connection connection;
private ConnectionProxy(Connection conn) {
super();
log.debug("Connection Id=" + id);
}
/*传说中的invoke,所有Connection .class 类调用的方法都要经过他分配,很流氓的东西
这里的类必须要实现InvocationHandler 接口,这样才有invoke 的由来
*/
public Object invoke(Object prox, Method method, Object[] params) throws Throwable {
try {
if ("prepareStatement".Name())) {
log.debug("ConnectionId=" + id + " Preparing Statement: " +
params[0].toString());
PreparedStatement stmt = (PreparedStatem ent) method.invoke(connection,
params); //这里才是真正的调用到该调用的文件
stmt = wInstance(stmt, (String) params[0]);
return stmt;//这里是出卖PreparedStatement.class 等文件给代理的。
} else if ("prepareCall".Name())) {
log.debug("ConnectionId=" + id + " prepareCall Statement: " +
params[0].toString());
PreparedStatement stmt = (PreparedStatem ent) method.invoke(connection,
params);
stmt = wInstance(stmt, (String) params[0]);
return stmt;
} else if ("createStatement".Nam e())) {
log.debug("ConnectionId=" + id + " createStatement: " +
params[0].toString());
Statement stmt = (Statem ent) method.invoke(connection, params);
stmt = wInstance(stmt);
return stmt;
} else {
return method.invoke(connection, params);
}
} catch (Throwable t) {
throw t;
}
}
/**
* 这里让这丫的Connection 也进入 proxy 的过滤文件列表
*/
public static Connection newInstance(Connection conn) {
InvocationHandler handler = new ConnectionProxy(conn);
ClassLoade r cl = ClassLoader();
/
*看这里,在这里Connection.class 被出卖了,到他的调用都要先被ConnectionProxy invoke 看看了,一下类我就不标注了*/
return (Connection) wProxyInstance(cl, new Class[] { Connection.class }, handler);
}
}
PreparedStatementProxy.java
package net.chinacsharp.proxy;
import flect.InvocationHandler;

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。