InvocationHandler is the interface implemented by the invocation handler of a proxy instance.
Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.
实现了InvocationHandler接口的
Object invoke(Object proxy, Method method, Object[] args)
Proxy 代理类
Method 调用的方法
Args 调用方法的参数
的方法的类可以作为InvocationHandler类的参数来构建Proxy类的实例
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 to
Example:
ConnectionWrapper(Connection con) {
Class[] interfaces = {
java.sql.Connection.class};
this.connection = (Connection) Proxy.newProxyInstance(
con.getClass().getClassLoader(),
interfaces, this);
m_originConnection = con;
}
作用说明:
当调用被代理的类(Connection)的实例的方法时系统将转到包含代理类(Proxy)的InvocationHandler的invoke方法中去执行相应代码。
这样就可以在不修改代码的前提下为已经存在的类来添加新的功能。
如:(全部代码参看DBConnectionPool.java)
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;
}
DBConnectionPool.java
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 hours
static { 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();
}
}