Saturday, October 21, 2017

Object pooling made simple using Apache Commons Pool2

If you are looking for a quick implementation of an object pool, then look no further than the excellent Apache Commons Pool2 implementation. Pool2 is far better and faster than the original commons pool library.

Object pool can be used to cache those objects that are expensive to setup and cannot be created for every request or thread - e.g. DB connections, MQTT broker connections, AMQP broker connections, etc. 

The following code snippets would show you how simple it is to create a pool for your 'expensive-to-create' objects. 
Any object pool typically requires 2 parameters  [GenericObjectPool.java] --- 
1) A factory object to handle creation and destruction of your objects [MyObjectFactory.java]
2) A configuration object to configure your pool. [GenericObjectPoolConfig,java]

import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
public class MyObjectFactory
extends BasePooledObjectFactory<MyObject> {
@Override
public MyObject create() {
//Put in your logic for creating your expensive object - e.g. JDBC Connection, MQTT Connection, etc.
//here for the sake of simplicity, we return a custom pooled object of a custom class called MyObject.
return new MyObject();
}
/**
* Use the default PooledObject implementation. This helps in acting like a proxy for doing extra operations.
* Please read API docs of DefaultPooledObject for more information
*/
@Override
public PooledObject<MyObject> wrap(MyObject myObject) {
return new DefaultPooledObject<MyObject>(myObject);
}
@Override
public void destroyObject(PooledObject<MyObject> p) {
//Destroys an instance no longer needed by the pool.
//Please put in your scavenging logic here...closing socket connections, mqtt broker connections, etc.
System.out.println("destroying");
}
// for all other methods, the no-op implementation
// in BasePooledObjectFactory will suffice
}
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
public class PoolDemo
{
public static void main(String[] args) throws Exception
{
//Create the Object pool.
ObjectPool pool = initializePool();
Object obj = null;
try {
obj = pool.borrowObject();
try {
//...use the object...
} catch(Exception e) {
// invalidate the object
pool.invalidateObject(obj);
// do not return the object to the pool twice
obj = null;
} finally {
// make sure the object is returned to the pool
if(null != obj) {
pool.returnObject(obj);
}
}
} catch(Exception e) {
// failed to borrow an object
}
}
//A helper method to initialize the pool using the config and object-factory.
public ObjectPool initializePool() throws Exception
{
// We confugure the pool using a GenericObjectPoolConfig
//Note: In the default implementation of Object Pool, objects are not created at start-up, but rather are created whenever the first call
//to the pool.borrowObject() is made. This object is then cached for future use.
//It is recommended to put these settings in a properties file.
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(3);
config.setBlockWhenExhausted(true);
config.setMaxWaitMillis(30 * 1000);
//We use the GenericObjectPool implementation of Object Pool as this suffices for most needs.
//When we create the object pool, we need to pass the Object Factory class that would be responsible for creating the objects.
//Also pass the config to the pool while creation.
ObjectPool pool = new GenericObjectPool<MyObject>(new MyObjectFactory(), config);
return pool;
}
}
view raw PoolDemo.java hosted with ❤ by GitHub

No comments:

Post a Comment