Look at the application of Design Pattern (7) from a ConnectionPool implementation (7)
Here is a bonmot on this Connection Pool:
The Pooled Connection may cause the entire pool to block due to a Client forgot to close. So, the Pooled Connection should be monitored, and the Pooled Connection for the timeout or other Invaild status is encycloped.
Below, let us analyze this demand.
First, what is the logic of such a monitoring process? If we define the timeout: This connection is too long from being assigned to now. So, we need to record the time to be assigned on the connection object. Then, regularly check these CONNECTIONs in a daemon thread in a background. If our timeout includes frequently extent to this Connection, this connection has not been moved for two hours, (Here, "moving" needs to be defined. As long as a member function is called, even if it is "moving"? Or all the objects generated from this connection, such as Statement, ResultSet, etc.?) To overload the method of our interest, record the time called the method.
Second, in general, how many coupling between monitoring the allocated connection and managing idle connections? Can you decouple them? After analysis, I feel that the answer is: can't. The algorithm that monitors the assigned connection is theoretically likely to know some of the information of idle connection, and it is the same. Moreover, more hateful is that the amount of information needed between them cannot be estimated, that is, for some specific algorithms, they may be completely fastened. If it is analyzed, this ConnectionPool may have to request the implementation directly to implement ConnectionPool, just like the method used in our third chapter, can only read some UTILITY classes, like the PooledConnection. However, although we cannot complete the monitoring algorithm and allocation algorithms. But in fact a lot of monitoring algorithms, allocation algorithms are indeed unrelated to each other. For example, like the needs we just analyze. So we may write a framework to simplify the implementation of these mutually discreputors. Although we have no power to completely adjustable, we can still act in most common situations. Moreover, such a frame does not affect the special implementation of complex tight coupling.
Ok, let's build this frame now. Our goal is to define a Monitor's interface and is responsible for monitoring all assigned connections. Then, combine a monitor object, a ConnectionPooling object into a connectionPool.
The algorithm determines the data structure, first of all, the time information is required: public interface momento {java.util.date getTimeStamp ();} Second, our monitoring classes need to know how to force a connection: public interface resourceProxy {Momento getBpterMomento (); Void release (); boolean isreleased ();} Note, here, our resourceProxy is not directly related to Connection. In this way, any resource can be monitored by our monitoring classes as long as this interface is implemented.
Then, the interface of the monitoring class: public interface resourceProxyMonitor {public void addressProxy (ResourceProxy Proxy);} This interface is called before the Connection is returned to ConnectionPool, and the allocated Connection is registered to the monitoring class.
Here is the monitor class: public class SimpleResourceProxyMonitor implements ResourceProxyMonitor {public synchronized void addResourceProxy (ResourceProxy proxy) {list.add (proxy);} private final java.util.List list = new java.util.LinkedList (); private final HeartBeatEngine hb = HeartBeatEngine.instance (); private final void releaseProxy (ResourceProxy proxy) {proxy.release ();} public final Runnable getMonitor (final long interval, final long ttl) {return hb.getThreadProc (interval, new HeartBeat () {Public boolean beat () {final java.util.date now = new java.util.date (); synchronized (simpleresourceProxyMonitor.this) {for (java.util.itrator it = list.iterator (); it.hasnext );) {Final ResourceProxy proxy = (resourceProxy) it.next (); final java.util.date kiln = proxy.getmomento (). GetTimeStamp (); if (now.gettime () - dam (now.getime () - THEN.GETTIME ()> = TTL) {ReleaseProxy (Proxy);} if (proxy.isreleased ()) {it.remove ();}}} return true;}});} Blic final synchronized void clear () {turnoffmonitors (); for (java.util.iterator it = list.iterator (); it.hasnext ();) {Final ResourceProxy proxy = (resourceProxy) it.next (); releaseproxy PROXY);} list.clear ();} public final synchronized void Empty () {turnoffmonitors (); list.clear ();} public final void TurnoniTors () {hb.turnon ();} public final void turnoffmonitors () {Hb.turnoff ();} private simpleresourceProxyMonitor () {} public static simpleresourceProxyMonitor Instance () {return new simpleresourceProxyMonitor ();}}
And two auxiliary interfaces and classes: HeartBeat and Heartbeatengine, responsible for the sleep and wake up of the daemon thread. public interface HeartBeat {public boolean beat (); file: // return true if continue, false otherwise;} public class HeartBeatEngine {public Runnable getThreadProc (final long interval, final HeartBeat r) {return new Runnable () {public void run ( ) {For (; ison ();};} catch (interruptedException e) {} synchronized (HeartBeatengine.this) {if (! Ison ()) return;} if (! R. beat ()) return;}}};} private boolean down = false; private HeartBeatEngine (boolean d) {this.down = d;} public final synchronized void turnon () {down = false;} public final synchronized void turnoff ( ) {Down = true;} private final boolean ison () {return! Down;} public static heartbeatengine instance () {return new heartbeatengine (false);}}
Here, getmonitor () only returns a runnable instead of directly starting Thread. This is more flexible. Customers using this Monitor class can freely use this runnable, such as, using a thread pool.
Then, we need a proxy class to record the time:
public class PooledConnectionProxy implements ResourceProxy {public final Momento getMomento () {return momento;} public void release () {try {conn.close ();} catch (SQLException e) {System.err.println (e.getMessage ()) }} File: // the conn.close () Method Has to be synchronized public boolean isreleased ();} catch (sqlexception e) {return false;}}. private final Connection conn; private PooledConnectionProxy (Momento momento, Connection conn) {this.momento = momento; this.conn = conn;} public static ResourceProxy instance (Momento momento, Connection conn) {return new PooledConnectionProxy (momento, conn);} }
Ok, now we can assemble them together and make a connectionpool. Remember our connectionPooling2Pool? It is responsible for encapsulating connectpooling and packages each connection. At that time, we wrote the package logic to ConnectionPooling2Pool because the package logic has only one. But now, we have another packaging logic. So, refactor. I know that people should know that I will not use Template Method Pattern to inherit ConnectionPooling2Pool and then overload the WRAPUP function. Use a combination! Encapsulation is a ConnectionPooler Connection of the interface: public interface ConnectionPooler {public Connection pool (Connection conn, ConnectionHome home) throws SQLException;} ConnectionPooling2Pool ConnectionPooler using encapsulation. public class ConnectionPooling2Pool implements ConnectionPool {public final Connection getConnection () throws test.res.ResourceNotAvailableException, SQLException {return wrapup (pooling.getConnection ());} public final Connection getConnection (long timeout) throws test.res.ResourceTimeOutException, SQLException {return wrapup (pooling.getConnection (timeout));} private final Connection wrapup (Connection conn) throws SQLException {return pl.pool (conn, pooling);} public final void clear () {pooling.clear ();} private final ConnectionPooling pooling; private final ConnectionPooler pl; private ConnectionPooling2Pool (ConnectionPooling pooling, ConnectionPooler pl) {this.pooling = pooling; this.pl = pl;} public static ConnectionPool bridge (ConnectionPooling pooling, ConnectionPooler pl) {return new ConnectionPooling2Pool (pooling, pl) }}
The original packing logic is implemented as: public class SimpleConnectionPooler implements ConnectionPooler {public Connection pool (Connection conn, ConnectionHome home) throws SQLException {return PooledConnection.decorate (conn, home);} private SimpleConnectionPooler () {} private static final ConnectionPooler singleton = new SimpleConnectionPooler (); public static ConnectionPooler instance () {return singleton;}} package our new logic: public class MonitoredConnectionPooler implements ConnectionPooler {public Connection pool (Connection conn, ConnectionHome home) throws SQLException {final Connection pooled = PooledConnection.decorate (conn, home); monitor.addResourceProxy (PooledConnectionProxy.instance (factory.newMomento (), pooled)); return pooled;} private final MomentoFactory factory; private final ResourceProxyMonitor monitor; private MonitoredConnectionPooler (ResourceProxyMonitor mon, MomentoFactory factory) {this. Monitor = MON; this.factory = Factory; PUBLIC STATIC ConnectionPool INSTAN ce (ResourceProxyMonitor mon, MomentoFactory factory) {return new MonitoredConnectionPooler (mon, factory);}} final composition code: public class TestConnectionPool {public static void test (String driver, String url, String user, String pwd) throws java. sql.SQLException, test.res.ResourceNotAvailableException, test.res.ResourceTimeOutException, ClassNotFoundException {final ConnectionPool pool = ConnectionPooling2Pool.bridge (ConnectionPoolingImpl.instance (ConnectionFactoryImpl.instance (driver, url, user, pwd), 1000), SimpleConnectionPooler.instance ( ))); Final SimpleResourceProxyMonitor Mon = SimpleResourceProxyMonitor .instance ();
final ConnectionPool pool2 = ConnectionPooling2Pool.bridge (ConnectionPoolingImpl.instance (ConnectionFactoryImpl.instance (driver, url, user, pwd), 1000), MonitoredConnectionPooler.instance (mon, SimpleMomentoFactory.instance ())); final Runnable monproc = mon.getMonitor ( 1000L, 1000000L); New Thread (MonProc) .Start ();}} Frequently monitoring the use of Connection, because the data structure required by the algorithm is different, so you will need your own ResourceProxy, ResourceProxyMonitor interface and Synchronize and record access times for Connection or even other Connection. But the mechanism of implementation is similar.