使用动态代理方法实现Method hook(转载)
本文来自csdn:http://topic.csdn.net/u/20071030/08/fa2e15dd-1abe-46dc-b76e-9fe2de4e7381.html
问题描述:有这样一个需求,有一个Hashtable存储着一些东西,而且已经序列化到了硬盘上,假如这个Hashtable发生了变化,就将这个新的Hashtable重新序列化到硬盘上,前提是并不知道哪些方法会改变这个Hashtable,这该怎么实现呢?
bao110908[火龙果]:最嘉的答案.
import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.Hashtable;import java.util.Map;public class HashtableProxyTest { public static void main(String[] args) { Map<String, String> table = new Hashtable<String, String>(); HashtableHandler handler = new HashtableHandler(); table = handler.bind(table); table.put("abc", "abc"); Map t1 = WriteFile.readFile(); System.out.println(t1.size()); m(table); t1 = WriteFile.readFile(); System.out.println(t1.size()); String abc = table.get("abc"); t1 = WriteFile.readFile(); System.out.println(t1.size()); System.out.println(abc); table.remove("abc"); t1 = WriteFile.readFile(); System.out.println(t1.size()); table.clear(); t1 = WriteFile.readFile(); System.out.println(t1.size()); } public static void m(Map<String, String> map) { map.put("123", "123"); }}class WriteFile { private static File file = new File("Hashtable.obj"); public static void writeFile(Map<String, String> map) { try { ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file)); out.writeObject(map); out.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } @SuppressWarnings("unchecked") public static Map<String, String> readFile() { Map map = null; try { ObjectInputStream in = new ObjectInputStream(new FileInputStream(file)); map = (Map<String, String>)in.readObject(); in.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return map; }}class HashtableHandler implements InvocationHandler { private Map<String, String> table = null; @SuppressWarnings("unchecked") public Map<String, String> bind(Map<String, String> map) { table = map; Map<String, String> mapProxy = (Map<String, String>)Proxy.newProxyInstance( table.getClass().getClassLoader(), table.getClass().getInterfaces(), this ); return mapProxy; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object obj = null; // 调用原有的方法 obj = method.invoke(table, args); String name = method.getName(); String changeMethod = "(clear)|(put)|(putAll)|(remove)"; // 当调用的方法为更改 map 中值的方法时,写入文件中 if(name.matches(changeMethod)) { WriteFile.writeFile(table); } return obj; }}
问题描述: 构造连接池。
来源:http://blog.csdn.net/Coolongxp/archive/2005/04/28/366107.aspx
实现了InvocationHandler接口的
Object invoke(Object proxy, Method method, Object[] args)
Proxy 代理类
Method 调用的方法
Args 调用方法的参数
的方法的类可以作为InvocationHandler类的参数来构建Proxy类的实例
<span style="color: #008000;">static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
loader - the class loader to define the proxy class in
interfaces - the list of interfaces for the proxy class to implement
h - the invocation handler to dispatch method invocations
ConnectionWrapper(Connection con) { Class[] interfaces = { java.sql.Connection.class}; this.connection = (Connection) Proxy.newProxyInstance( con.getClass().getClassLoader(), interfaces, this); m_originConnection = con;}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { Object obj = null; if (CLOSE_METHOD_NAME.equals(m.getName())) { DBConnectionPool.pushConnectionBackToPool(this); } else { obj = m.invoke(m_originConnection, args); } if (DEBUG) { System.out.println(m.getName()+"is invoke!"); } lastAccessTime = System.currentTimeMillis(); return obj;}
作用说明:
当调用被代理的类(Connection)的实例的方法时系统将转到包含代理类(Proxy)的InvocationHandler的invoke方法中去执行相应代码。
这样就可以在不修改代码的前提下为已经存在的类来添加新的功能。
如:(全部代码参看DBConnectionPool.java)
<div class="dp-highlighter"><div class="bar">import java.sql.*;import java.lang.reflect.*;import java.util.*;import java.io.*;public class DBConnectionPool {private static LinkedList m_notUsedConnection = new LinkedList();private static HashSet m_usedUsedConnection = new HashSet();private static String m_url = "";private static String m_user = "";private static String m_password = "";static final boolean DEBUG = true;static private long m_lastClearClosedConnection = System.currentTimeMillis();public static long CHECK_CLOSED_CONNECTION_TIME = 4 * 60 * 60 * 1000; //4 hoursstatic { initDriver();}private DBConnectionPool() {}private static void initDriver() { Driver driver = null;//load mysql driver try { driver = (Driver) Class.forName( "com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance(); installDriver(driver); } catch (Exception e) { }//load postgresql driver try { driver = (Driver) Class.forName("org.postgresql.Driver").newInstance(); installDriver(driver); } catch (Exception e) { }}public static void installDriver(Driver driver) { try { DriverManager.registerDriver(driver); } catch (Exception e) { e.printStackTrace(); }}public static synchronized Connection getConnection() { clearClosedConnection(); while (m_notUsedConnection.size() > 0) { try { ConnectionWrapper wrapper = (ConnectionWrapper) m_notUsedConnection. removeFirst(); if (wrapper.connection.isClosed()) { continue; } m_usedUsedConnection.add(wrapper); if (DEBUG) { wrapper.debugInfo = new Throwable("Connection initial statement"); } return wrapper.connection; } catch (Exception e) { } } int newCount = getIncreasingConnectionCount(); LinkedList list = new LinkedList(); ConnectionWrapper wrapper = null; for (int i = 0; i < newCount; i++) { wrapper = getNewConnection(); if (wrapper != null) { list.add(wrapper); } } if (list.size() == 0) { return null; } wrapper = (ConnectionWrapper) list.removeFirst(); m_usedUsedConnection.add(wrapper); m_notUsedConnection.addAll(list); list.clear(); return wrapper.connection;}private static ConnectionWrapper getNewConnection() { try { Connection con = DriverManager.getConnection(m_url, m_user, m_password); ConnectionWrapper wrapper = new ConnectionWrapper(con); return wrapper; } catch (Exception e) { e.printStackTrace(); } return null;}static synchronized void pushConnectionBackToPool(ConnectionWrapper con) { boolean exist = m_usedUsedConnection.remove(con); if (exist) { m_notUsedConnection.addLast(con); }}public static int close() { int count = 0; if(DEBUG){ System.out.println("it is DBConnection's close()"); } Iterator iterator = m_notUsedConnection.iterator(); while (iterator.hasNext()) { try { ( (ConnectionWrapper) iterator.next()).close(); count++; } catch (Exception e) { } } m_notUsedConnection.clear(); iterator = m_usedUsedConnection.iterator(); while (iterator.hasNext()) { try { ConnectionWrapper wrapper = (ConnectionWrapper) iterator.next(); wrapper.close(); if (DEBUG) { wrapper.debugInfo.printStackTrace(); } count++; } catch (Exception e) { } } m_usedUsedConnection.clear(); return count;}private static void clearClosedConnection() { long time = System.currentTimeMillis();//sometimes user change system time,just return if (time < m_lastClearClosedConnection) { time = m_lastClearClosedConnection; return; }//no need check very often if (time - m_lastClearClosedConnection < CHECK_CLOSED_CONNECTION_TIME) { return; } m_lastClearClosedConnection = time;//begin check Iterator iterator = m_notUsedConnection.iterator(); while (iterator.hasNext()) { ConnectionWrapper wrapper = (ConnectionWrapper) iterator.next(); try { if (wrapper.connection.isClosed()) { iterator.remove(); } } catch (Exception e) { iterator.remove(); if (DEBUG) { System.out.println( "connection is closed, this connection initial StackTrace"); wrapper.debugInfo.printStackTrace(); } } }//make connection pool size smaller if too big int decrease = getDecreasingConnectionCount(); if (m_notUsedConnection.size() < decrease) { return; } while (decrease-- > 0) { ConnectionWrapper wrapper = (ConnectionWrapper) m_notUsedConnection. removeFirst(); try { wrapper.connection.close(); } catch (Exception e) { } }}/** * get increasing connection count, not just add 1 connection * @return count */public static int getIncreasingConnectionCount() { int count = 1; int current = getConnectionCount(); count = current / 4; if (count < 1) { count = 1; } return count;}/** * get decreasing connection count, not just remove 1 connection * @return count */public static int getDecreasingConnectionCount() { int count = 0; int current = getConnectionCount(); if (current < 10) { return 0; } return current / 3;}public synchronized static void printDebugMsg() { printDebugMsg(System.out);}public synchronized static void printDebugMsg(PrintStream out) { if (DEBUG == false) { return; } StringBuffer msg = new StringBuffer(); msg.append("debug message in " + DBConnectionPool.class.getName()); msg.append("\r\n"); msg.append("total count is connection pool: " + getConnectionCount()); msg.append("\r\n"); msg.append("not used connection count: " + getNotUsedConnectionCount()); msg.append("\r\n"); msg.append("used connection, count: " + getUsedConnectionCount()); out.println(msg); Iterator iterator = m_usedUsedConnection.iterator(); while (iterator.hasNext()) { ConnectionWrapper wrapper = (ConnectionWrapper) iterator.next(); wrapper.debugInfo.printStackTrace(out); } out.println();}public static synchronized int getNotUsedConnectionCount() { return m_notUsedConnection.size();}public static synchronized int getUsedConnectionCount() { return m_usedUsedConnection.size();}public static synchronized int getConnectionCount() { return m_notUsedConnection.size() + m_usedUsedConnection.size();}public static String getUrl() { return m_url;}public static void setUrl(String url) { if (url == null) { return; } m_url = url.trim();}public static String getUser() { return m_user;}public static void setUser(String user) { if (user == null) { return; } m_user = user.trim();}public static String getPassword() { return m_password;}public static void setPassword(String password) { if (password == null) { return; } m_password = password.trim();}}class ConnectionWrapper implements InvocationHandler {private final static String CLOSE_METHOD_NAME = "close";public Connection connection = null;private Connection m_originConnection = null;static final boolean DEBUG = true;public long lastAccessTime = System.currentTimeMillis();Throwable debugInfo = new Throwable("Connection initial statement");ConnectionWrapper(Connection con) { Class[] interfaces = { java.sql.Connection.class}; this.connection = (Connection) Proxy.newProxyInstance( con.getClass().getClassLoader(), interfaces, this); m_originConnection = con;}void close() throws SQLException { if(DEBUG){ System.out.println("it is close method"); } m_originConnection.close();}public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { Object obj = null; if (CLOSE_METHOD_NAME.equals(m.getName())) { DBConnectionPool.pushConnectionBackToPool(this); } else { obj = m.invoke(m_originConnection, args); } if (DEBUG) { System.out.println(m.getName()+"is invoke!"); } lastAccessTime = System.currentTimeMillis(); return obj;}public static void main(String[] args) { DBConnectionPool.setUrl( "jdbc:microsoft:sqlserver://192.168.0.76:1433;DatabaseName=sms_misc"); DBConnectionPool.setUser("lhf"); DBConnectionPool.setPassword("lhf"); Connection con = DBConnectionPool.getConnection(); Connection con1 = DBConnectionPool.getConnection(); Connection con2 = DBConnectionPool.getConnection();//do something with con ... try { Statement stmt1 = con.createStatement(); Statement stmt2 = con1.createStatement(); Statement stmt3 = con2.createStatement(); for (int i = 0; i < 10; i++) { // stmt1.executeUpdate("exec testyh"); // stmt2.executeUpdate("update yhgatemt_v3 set yh_status='wait'"); // stmt3.executeUpdate("update yhgatemt_v3 set yh_status='past'"); } } catch (Exception e) { System.out.println("error"); } try { System.out.println("Closing con"); con.close(); } catch (Exception e) {} try { System.out.println("Closing con1"); con1.close(); } catch (Exception e) {} try { System.out.println("Closing con2"); con2.close(); } catch (Exception e) {} con = DBConnectionPool.getConnection(); con1 = DBConnectionPool.getConnection(); try { con1.close(); } catch (Exception e) {} con2 = DBConnectionPool.getConnection(); DBConnectionPool.printDebugMsg();}}
页:
[1]