JavaProxy动态代理详解传说中的AOP的一个应用,(我读ibatis)_第1页
JavaProxy动态代理详解传说中的AOP的一个应用,(我读ibatis)_第2页
JavaProxy动态代理详解传说中的AOP的一个应用,(我读ibatis)_第3页
JavaProxy动态代理详解传说中的AOP的一个应用,(我读ibatis)_第4页
JavaProxy动态代理详解传说中的AOP的一个应用,(我读ibatis)_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

java.lang.reflect.Proxy对象是对class文件的调用起到一个代理作用个方法的调用首先都要经过proxy的处理方法。然后在proxy的处理方法(invoke方法)里面才真正的目的class里面的方法。。对每于目的class中的开始调用例如:Testt=newTest();t.print(null)在没有使用代理的情况下,这里的print方法的调用应该是直接到Test类里面调用InvocationHandler对象(类)的时候。也就是把这个Test类出卖给了方法就要通过Proxy的处理方法invoke(实现说“被双规了”这个方法了。这里当把Test类绑定到Proxy,这样如果要是再想调用Test类里面的InvocationHandler接口的)了。有那里调用。简单的下面我们就来通过这个特性来做一个数据库操作的日志记录过滤器。在我们程序运行中,数据库调用阶段的日志对我们分析程序的错误很有参考价值。这里我们就做一个代理的过滤器,用于记录对数据库的读取,更新等一数据库执行的SQL,SQL的参数等。可谓意义还是有点的啦,这里老孙经过一鼓的程序供大家参考。本文为参看ibatis源代码。网上有人说这玩意就是AOP,我才不管它是啥P呢,能满足我的要求便可。系列操作的接口日志的详细记录的过滤程序。用于记录调用天的调试整理,捣这里我们创建5个java文件BaseProxy.java代理实现基类ConnectionProxy.java用于记录调用PreparedStatementProxy.java用于记录PreparedStatement对象的ResultSetProxy.java用于记录ResultSet对象时候的日志。时候的日志。connection对象的时候记录日志。方法调用过程的日志记录方法调用的StatementProxy.java用于记录Statement对象方法调用这里开始铺设源代码BaseProxy.java这个文件是基础类,用于存放一些公共的参数,方法名称,还有调用SQL的时候我们最关注的绑定变量的参数。packagexy;importjava.util.ArrayList;importjava.util.HashMap;importjava.util.HashSet;importjava.util.List;importjava.util.Map;importjava.util.Set;publicclassBaseProxy{/***存放statement对象的set方法。*/protectedstaticfinalSetsetMethods=newHashSet();/***存放statement对象的get方法。*/protectedstaticfinalSetgetMethods=newHashSet();

/***存放statement对象的exec的几个方法。*/protectedstaticfinalSetexecSqlMethods=newHashSet();privateMapparamsMap=newHashMap();privateListparamsNames=newArrayList();privateListparamsValues=newArrayList();/***初始id,用于确定Proxy的同一个对象*/privatestaticintnextId=100000;/***用于确定Proxy的同一个对象*/protectedintid;static{setMethods.add("setString");setMethods.add("setInt");setMethods.add("setByte");setMethods.add("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("setNull");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("getDate");getMethods.add("getTime");getMethods.add("getArray");getMethods.add("getBigDecimal");getMethods.add("getAsciiStream");getMethods.add("getBinaryStream");getMethods.add("getBlob");getMethods.add("getBoolean");getMethods.add("getBytes");getMethods.add("getCharacterStream");getMethods.add("getClob");getMethods.add("getObject");getMethods.add("getNull");execSqlMethods.add("execute");execSqlMethods.add("executeUpdate");execSqlMethods.add("executeQuery");}publicBaseProxy(){id=getNextId();}/***用于取得proxy调用对象的id,这里防止id重复,所以是同步的*@return*/protectedsynchronizedstaticintgetNextId(){returnnextId++;}protectedvoidsetColumn(Objectkey,Objectvalue){paramsMap.put(key,value);paramsNames.add(key);paramsValues.add(value);}protectedObjectgetColumn(Objectkey){returnparamsMap.get(key);}protectedStringgetValueString(){returnparamsValues.toString();}protectedStringgetTypeString(){ListtypeList=newArrayList(paramsValues.size());for(inti=0;i<paramsValues.size();i++){Objectvalue=paramsValues.get(i);if(value==null){

typeList.add("null");}else{typeList.add(value.getClass().getName());}}returntypeList.toString();}protectedStringgetColumnString(){returnparamsNames.toString();}protectedvoidclearColumnInfo(){paramsMap.clear();paramsNames.clear();paramsValues.clear();}}ConnectionProxy.java这个类把调用conncetion的无论哪个方法在invoke方法这里connection方法装到了proxy代理过滤文件列表里面。这里,其实都要先通过ConnectionProxy类的invoke方法,我们记录下调用的日志情况:packagexy;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;importjava.sql.Connection;importjava.sql.PreparedStatement;importjava.sql.Statement;importmons.logging.Log;importmons.logging.LogFactory;/***本类用于记录Connection一层的日志*/publicclassConnectionProxyextendsBaseProxyimplementsInvocationHandler{privatestaticfinalLoglog=LogFactory.getLog(ConnectionProxy.class);privateConnectionconnection;privateConnectionProxy(Connectionconn){super();this.connection=conn;log.debug("ConnectionId="+id);}/*传说中的invoke,所有Connection.class类调用的方法都要经过他分配,很流氓的东西这里的类必须要实现InvocationHandler接口,这样才有invoke的由来*/publicObjectinvoke(Objectprox,Methodmethod,Object[]params)throwsThrowable{

try{if("prepareStatement".equals(method.getName())){log.debug("ConnectionId="+id+"PreparingStatement:"+params[0].toString());PreparedStatementstmt=(PreparedStatement)method.invoke(connection,params);//这里才是真正的调用到该调用的文件stmt=PreparedStatementProxy.newInstance(stmt,(String)params[0]);returnstmt;//这里是出卖PreparedStatement.class等文件给代理的。}elseif("prepareCall".equals(method.getName())){log.debug("ConnectionId="+id+"prepareCallStatement:"+params[0].toString());PreparedStatementstmt=(PreparedStatement)method.invoke(connection,params);stmt=PreparedStatementProxy.newInstance(stmt,(String)params[0]);returnstmt;}elseif("createStatement".equals(method.getName())){log.debug("ConnectionId="+id+"createStatement:"+params[0].toString());Statementstmt=(Statement)method.invoke(connection,params);stmt=StatementProxy.newInstance(stmt);returnstmt;}else{returnmethod.invoke(connection,params);}}catch(Throwablet){throwt;}}/***这里让这丫的Connection也进入proxy的过滤文件列表*/publicstaticConnectionnewInstance(Connectionconn){InvocationHandlerhandler=newConnectionProxy(conn);ClassLoadercl=Connection.class.getClassLoader();/*看这里Connection.class被出卖他的调用都要先被ConnectionProxyinvoke看看,在这里了,到了,一下类我就不标注了*/return(Connection)Proxy.newProxyInstance(cl,newClass[]{Connection.class},handler);}}PreparedStatementProxy.javapackagexy;importjava.lang.reflect.InvocationHandler;

importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;importjava.sql.CallableStatement;importjava.sql.PreparedStatement;importjava.sql.ResultSet;importmons.logging.Log;importmons.logging.LogFactory;/***本类用于记录PreparedStatement的日志*/publicclassPreparedStatementProxyextendsBaseProxyimplementsInvocationHandler{privatestaticfinalLoglog=LogFactory.getLog(PreparedStatement.class);privatePreparedStatementstatement;privateStringsql;privatePreparedStatementProxy(PreparedStatementstmt,Stringsql){this.statement=stmt;this.sql=sql;}publicObjectinvoke(Objectproxy,Methodmethod,Object[]params)throwsThrowable{try{if(execSqlMethods.contains(method.getName())){log.debug("PreparedStatementId="+id+"ExecutingStatement:"+sql);log.debug("PreparedStatementId="+id+"Parameters:"+getValueString());log.debug("PreparedStatementId="+id+"Types:"+getTypeString());if("executeQuery".equals(method.getName())){ResultSetrs=(ResultSet)method.invoke(statement,params);if(rs!=null){returnResultSetProxy.newInstance(rs);}else{returnnull;}}else{returnmethod.invoke(statement,params);}}elseif(setMethods.contains(method.getName())){if("setNull".equals(method.getName())){setColumn(params[0],null);}else{//这里记录那些绑定变量的参数了setColumn(params[0],params[1]);}returnmethod.invoke(statement,params);

}elseif("getResultSet".equals(method.getName())){ResultSetrs=(ResultSet)method.invoke(statement,params);if(rs!=null){returnResultSetProxy.newInstance(rs);}else{returnnull;}}elseif("equals".equals(method.getName())){Objectps=params[0];if(psinstanceofProxy){returnnewBoolean(proxy==ps);}returnnewBoolean(false);}elseif("hashCode".equals(method.getName())){returnnewInteger(proxy.hashCode());}else{returnmethod.invoke(statement,params);}}catch(Throwablet){throwt;}}/***这个方法里面,PreparedStatement.class,CallableStatement.class有这两个方法被出卖给了PreparedStatementProxy,这里调用这两个类的方法,都要先被invoke方法看看了*/publicstaticPreparedStatementnewInstance(PreparedStatementstmt,Stringsql){InvocationHandlerhandler=newPreparedStatementProxy(stmt,sql);ClassLoadercl=PreparedStatement.class.getClassLoader();return(PreparedStatement)Proxy.newProxyInstance(cl,newClass[]{PreparedStatement.class,CallableStatement.class},handler);}}ResultSetProxy.java这里记录ResultSet里面的方法的调用。这个类的每个方法的调用都会被记录packagexy;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;importjava.sql.ResultSet;importmons.logging.Log;importmons.logging.LogFactory;/***@authorkeyboardsun*******************

*@site**/publicclassResultSetProxyextendsBaseProxyimplementsInvocationHandler{privatestaticfinalLoglog=LogFactory.getLog(ResultSet.class);booleanfirst=true;privateResultSetrs;privateResultSetProxy(ResultSetrs){super();this.rs=rs;log.debug("ResultSetId="+id+"ResultSet");}publicObjectinvoke(Objectproxy,Methodmethod,Object[]params)throwsThrowable{try{Objecto=method.invoke(rs,params);if(getMethods.contains(method.getName())){if(params[0]instanceofString){setColumn(params[0],o);}}elseif("next".equals(method.getName())||"close".equals(method.getName())){Strings=getValueString();if(!"[]".equals(s)){if(first){first=false;log.debug("ResultSetId="+id+"Header:"+getColumnString());}log.debug("ResultSetId="+id+"Result:"+s);}clearColumnInfo();}returno;}catch(Throwablet){throwt;}}/***这里ResultSet.class被出卖*/publicstaticResultSetnewInstance(ResultSetrs){InvocationHandlerhandler=newResultSetProxy(rs);ClassLoadercl=ResultSet.class.getClassLoader();return(ResultSet)Proxy.newProxyInstance(cl,newClass[]{ResultSet.class},

handler);}/***Getthewrappedresultset*@returntheresultSet*/publicResultSetgetRs(){returnrs;}}StatementProxy.java这里Statement类的所有方法的调用也要被记录的。packagexy;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;importjava.sql.ResultSet;importjava.sql.Statement;importmons.logging.Log;importmons.logging.LogFactory;/***@authorkeyboardsun********************@site**/publicclassStatementProxyextendsBaseProxyimplementsInvocationHandler{privatestaticfinalLoglog=LogFactory.getLog(Statement.class);privateStatementstatement;privateStatementProxy(Statementstmt){super();this.statement=stmt;}publicObjectinvoke(Objectproxy,Methodmethod,Object[]params)throwsThrowable{try{if(execSqlMethods.contains(method.getName())){log.debug("StatementId="+id+"Statement:"+params[0].toString());if("executeQuery".equals(method.getName())){ResultSetrs=(ResultSet)method.invoke(statement,params);if(rs!=null){returnResultSetProxy.newInstance(rs);}else{returnnull;}}else{

returnmethod.invoke(statement,params);}}elseif("getResultSet".equals(method.getName())){ResultSetrs=(ResultSet)method.invoke(statement,params);if(rs!=null){returnResultSetProxy.newInstance(rs);}else{returnnull;}}elseif("equals".equals(method.getName())){Objectps=params[0];if(psinstanceofProxy){returnnewBoolean(proxy==ps);}returnnewBoolean(false);}elseif("hashCode".equals(method.getName())){returnnewInteger(proxy.hashCode());}else{returnmethod.invoke(statement,params);}}catch(Throwablet){throwt;}}/***Statement.class被出卖*/publicstaticStatementnewInstance(Statementstmt){InvocationHandlerhandler=newStatementProxy(stmt);ClassLoadercl=Statement.class.getClassLoader();return(Statement)Proxy.newProxyInstance(cl,newClass[]{Statement.class},handler);}}这里我们把整个过滤的框架都写好了,入口就是上面的ConnectonProxy.java的newInstancenewInstance方法就可以了少写了很多debug的代码噢。方法,在我们的程序应用中,获取连接的时候只要通过这个。下面开始测试demo啦。各位look,效果不错噢,让我们packagenet.chinacsharp.main;importjava.sql.Connection;importjava.sql.DriverManager;importjava.sql.PreparedStatement;importjava.sql.ResultSet;importjava.util.ArrayList;importxy.ConnectionProxy;

publicclassRunTest{privatestaticConnectiongetConnection()throwsThrowable{Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();Connectionconn=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ORACLEDB","password");"uwfe",returnConnectionProxy.newInstance(conn);//这里,因为这段代码,数据库的操作类全部被出卖给了Proxy}publicstaticvoidmain(Stringargs[]){try{Connectionconnection=getConnection();PreparedStatementstatement=null;statement=connection.prepareStatement("select*fromwork_flow_taskwhereTASK_TYPE_CODE=?ANDTASK_TYPE_NAME=?");statement.setString(1,"task/综合室/station/ZHSXZHFCL.zhsxzhfjd");statement.setString(2,"综合室协作回复阶段");ResultSetrs=statement.executeQuery();while(set.next()){System.out.println(set.getString("TASK_TYPE_CODE"));System.out.println(set.getString("TASK_TYPE_NAME"));}}catch(Throwablee){e.printStackTrace();}}}这里我们跑一下,看看日志:注:这里的蓝色的说明是我加上去的。DEBUGxy.ConnectionProxy-ConnectionId=100000DEBUGxy.ConnectionProxy-ConnectionId=100000PreparingStatement:select*fromwork_flow_taskwhereTASK_TYPE_CODE=?ANDTASK_TYPE_NAME=?DEBUGjava.sql.PreparedStatement-PreparedStatementId=100001ExecutingStatement:select*fromwork_flow_taskwhereTASK_TYPE_CODE=?ANDTASK_TYPE_NAME=?DEBUGjava.sql.PreparedStatement-PreparedStatementId=100001Parameters:[task/综合室/station/ZHSXZHFCL.zhsxzhfjd,综合室协作回复阶段]//这里是set变量的职DEBUGjava.sql.PreparedStatement-PreparedStatementId=100001Types:[java.lang.String,java.lang.String]//set变量

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论