Pooling, convolution, and pooling
For objects that take a long time to create or occupy a large amount of resources, such as network connections and threads, pooling is usually used to manage these objects to improve performance. For example, the database connection pool (c3p0, dbcp) and java thread pool ExecutorService. apache Commons Pool provides a set of pooled and standardized interfaces to implement general logic. We only need to implement the Methods Abstracted from them. Commons Pool mainly has the following objects: PooledObject: This is the resource that needs to be pooled. Pooled objects can be extracted from common attributes, such as creation time and status, pooledObjectFactory, such as the last use time, is an object factory that creates, verifies, and destroys PooledOjbect. ObjectPool is an object pool that deals directly with object users, if you provide users with the object to be retrieved and the returned object interface is not very good in English, you may be confused by the names of these objects. In fact, everything in the world can be understood. If you compare a library's book to a PooledObject, the Library is the ObjectPool. To manage the book, the library adds the attributes for management, such as the Book Receiving time and book borrowing status. The Library (ObjectPool) provides the services (that is, interfaces) for the borrower to borrow and return books ). The actual work of books (PooledObject) printing, quality inspection, recycling (somewhat unrealistic) has to be handed over to the printing factory (PooledObjectFactory. The process relationship is as follows: Let's take a look at how to use the Commons Pool to implement your own object Pool. Creating your own object pool generally requires the following work: 1. first, you have compiled your resource object (this part does not belong to pooled content), and then compiled the Factory class that implements the apache PooledObjectFactory <T> interface, this is the main task of writing your own object pool. Your Factory may need to add some parameters for initialization of pooled objects, verification of pooled objects, and other parameters as member variables. 2. compile your own Pool class to inherit from or internally reference apache's GenericObjectPool <T>. GenericObjectPool implements the ObjectPool interface and encapsulates the lifecycle management logic for pooled objects. the optional part inherits from apache's GenericObjectPoolConfig, overwrites the constructor, and adds initialization parameters suitable for your business scenario. Let's take the source code of Jedis as an example to learn its implementation. Let's take a look at a simple example of using JedisPool to operate Redis.
Package com. eg. test. redis; import redis. clients. jedis. jedis; import redis. clients. jedis. jedisPool; import redis. clients. jedis. jedisPoolConfig; public class TestPool {public static void main (String [] args) {// JedisPoolConfig inherits apache's GenericObjectPoolConfig. The related parameters for configuring the Pool are as follows: JedisPoolConfig config = new JedisPoolConfig (); // if the value is-1, there is no restriction. If maxActive jedis instances have been allocated to the pool, the pool status is exhausted (depletion ). Config. setMaxTotal (500); // controls the maximum number of idle jedis instances in a pool. Config. setMaxIdle (5); // indicates the maximum waiting time when borrow (introduced) is a jedis instance. If the waiting time is exceeded, JedisConnectionException is thrown directly; config. setMaxWaitMillis (30000); // whether to perform the validate operation in advance when a jedis instance is in borrow; if it is true, the jedis instance is available; config. setTestOnBorrow (true); JedisPool pool = new JedisPool (config, "192.168.2.191", 8888); // obtain the Jedis jedis = pool from the pool. getResource (); String value = jedis. get ("someKey ");}}
First, let's look at the implementation of JedisFactory:
Class JedisFactory implements extends <Jedis> {private final AtomicReference <HostAndPort> hostAndPort = new AtomicReference <HostAndPort> (); private final int connectionTimeout; private final int soTimeout; // The constructor is omitted, are some operations to initialize member variables @ Override public void activateObject (PooledObject <Jedis> pooledJedis) throws Exception {final BinaryJedis jedis = pooledJedis. getObject (); if (jedis. getDB ()! = Database) {jedis. select (database) ;}@ Override public void destroyObject (PooledObject <Jedis> pooledJedis) throws Exception {final BinaryJedis jedis = pooledJedis. getObject (); if (jedis. isConnected () {try {jedis. quit ();} catch (Exception e) {} jedis. disconnect ();} catch (Exception e) {}}@ Override public PooledObject <Jedis> makeObject () throws Exception {final HostAndPort host AndPort = this. hostAndPort. get (); final Jedis jedis = new Jedis (hostAndPort. getHost (), hostAndPort. getPort (), connectionTimeout, soTimeout, ssl, sslSocketFactory, sslParameters, hostnameVerifier); try {jedis. connect (); if (null! = This. password) {jedis. auth (this. password) ;}if (database! = 0) {jedis. select (database);} if (clientName! = Null) {jedis. clientSetname (clientName) ;}} catch (JedisException je) {jedis. close (); throw je;} return new DefaultPooledObject <Jedis> (jedis);} @ Override public void passivateObject (PooledObject <Jedis> pooledJedis) throws Exception {// TODO maybe shocould select db 0? Not sure right now .} @ Override public boolean validateObject (PooledObject <Jedis> pooledJedis) {final BinaryJedis jedis = pooledJedis. getObject (); try {HostAndPort hostAndPort = this. hostAndPort. get (); String connectionHost = jedis. getClient (). getHost (); int connectionPort = jedis. getClient (). getPort (); return hostAndPort. getHost (). equals (connectionHost) & hostAndPort. getPort () = connectionPort & jedis. isConnected () & jedis. ping (). equals ("PONG");} catch (final Exception e) {return false ;}}}
We can see that there are few JedisFactory codes, but the logic is very clear. The Factory will act as a member variable of the ObjectPool. Four of the override methods are called when the ObjectPool manages the object lifecycle. The makeobject () method is used to create a Jedis instance. After the connect () method is successfully called to establish a stateful socket connection, a DefaultPooledObject object encapsulated with jedis is returned, defaultPooledObject implements the PooledObject interface for collecting the status information of pooled objects. The validateObject () method is used to check the object status. The status of the Jedis object is verified by the ping-pong method of the socket to check whether the connection is normal. The destroyObject () method is used to destroy objects. The Jedis object will be disconnected and resources will be recycled.
Let's look at the implementation of JedisPool. Because JedisPool inherits the Pool <T>, we mainly look at some code of the Pool <T>:
public abstract class Pool<T> implements Closeable { protected GenericObjectPool<T> internalPool; public Pool(final GenericObjectPoolConfig poolConfig, PooledObjectFactory<T> factory) { initPool(poolConfig, factory); } public boolean isClosed() { return this.internalPool.isClosed(); } public void initPool(final GenericObjectPoolConfig poolConfig, PooledObjectFactory<T> factory) { if (this.internalPool != null) { try { closeInternalPool(); } catch (Exception e) { } } this.internalPool = new GenericObjectPool<T>(factory, poolConfig); } public T getResource() { try { return internalPool.borrowObject(); } catch (NoSuchElementException nse) { throw new JedisException("Could not get a resource from the pool", nse); } catch (Exception e) { throw new JedisConnectionException("Could not get a resource from the pool", e); } } protected void returnResourceObject(final T resource) { if (resource == null) { return; } try { internalPool.returnObject(resource); } catch (Exception e) { throw new JedisException("Could not return the resource to the pool", e); } } public void addObjects(int count) { try { for (int i = 0; i < count; i++) { this.internalPool.addObject(); } } catch (Exception e) { throw new JedisException("Error trying to add idle objects", e); } }}
By referencing GenericObjectPool internally, JedisPool encapsulates the modifier mode of its interface, which is more flexible than inheritance. The JedisPool constructor needs to use JedisFactory and JedisPoolConfig to create a standard ObjectPool as its own member variable. Therefore, the pool. getResource () method still calls PoolObject. borrowObject (). Finally, let's take a look at JedisPoolConfig, but we have done some pre-initialization parameter work.
public class JedisPoolConfig extends GenericObjectPoolConfig { public JedisPoolConfig() { // defaults to make your life with connection pool easier :) setTestWhileIdle(true); setMinEvictableIdleTimeMillis(60000); setTimeBetweenEvictionRunsMillis(30000); setNumTestsPerEvictionRun(-1); }}