通常一个对象创建/销毁的时候非常耗时,我们不会频繁的创建销毁它,而是考虑复用。复用对象的一种做法就是对象池,将创建好的对象放入池中维护起来,下次再用的时候直接拿池中已经创建好的对象继续用
GenericObjectPool
GenericObjectPool
是一个通用对象池框架,我们可以借助它实现一个健壮的对象池
维护一个对象池需要实现以下基本的功能:
-
创建对象
-
借出对象
-
验证对象
-
归还对象
-
销毁对象
GenericObjectPool 需要通过构造器注入一个PooledObjectFactory
对象,而PooledObjectFactory
中提供了维护对象池的方法
public interface PooledObjectFactory<T> {
PooledObject<T> makeObject() throws Exception;
void destroyObject(PooledObject<T> var1) throws Exception;
boolean validateObject(PooledObject<T> var1);
void activateObject(PooledObject<T> var1) throws Exception;
void passivateObject(PooledObject<T> var1) throws Exception;
}
以Socket连接池为例
public class ConnectionFactory extends BasePooledObjectFactory<Socket> {
// 创建socket对象
public Socket create() throws Exception {
String[] ipAndPort = host.split(":");
if (ipAndPort.length < 2) {
throw new ParseHostException();
}
Integer port = Integer.parseInt(ipAndPort[1]);
Socket socket = new Socket(ipAndPort[0], port);
socket.setSoTimeout(timeOut);
return socket;
}
// 包装为可维护的对象
public PooledObject<Socket> wrap(Socket socket) {
return new DefaultPooledObject<Socket>(socket);
}
/**
* 能关的都给他关了
* @param pooledObject
* @throws Exception
*/
public void destroyObject(PooledObject<Socket> pooledObject) throws Exception {
Socket socket = pooledObject.getObject();
if (socket != null) {
socket.getInputStream().close();
socket.getOutputStream().close();
socket.close();
}
}
// 验证对象,Pool对象可以设置借出归还时候是否需要验证对象
public boolean validateObject(PooledObject<Socket> pooledObject) {
Socket socket = pooledObject.getObject();
return socket != null && !socket.isClosed() && socket.isConnected();
}
/**
* 钝化归还对象,说白了就是对归还的对象清理
* 清空输入流,避免因为上一个请求字节未读取完导致inputStream非空,对下一个产生影响
* @param p
* @throws Exception
*/
@Override
public void passivateObject(PooledObject<Socket> p) throws Exception {
Socket socket = p.getObject();
InputStream inputStream = socket.getInputStream();
int available = inputStream.available();
if (available > 0) {
inputStream.skip(available);
}
}
}
有了上面的ConnectionFactory,就可以创建对象池了
public class ConnectionPoolExecutor implements Executor {
private GenericObjectPool<Socket> connectionPool = new GenericObjectPool<>(new ConnectionFactory());
private String host;
private int timeOut = 5000;
// 池的大小
private int poolSize = 5;
// 最少空闲对象个数
private int miniIdle = 0;
// 最大空闲对象个数
private int maxIdle = poolSize;
// 驱除策略,对象池内部维护了一个定时线程,如果配置了此属性,会定时调用此类来校验对象是否可用
private String evictionPolicyClassName;
// 驱除对象的定时线程执行间隔
private int timeBetweenEvictionRunsMillis=5000;
// 驱除对象的定时线程每次校验对象个数
private int numTestsPerEvictionRun = 1;
public ConnectionPoolExecutor() {
this.connectionPool.setTestOnBorrow(true);
this.connectionPool.setTestOnReturn(true);
this.connectionPool.setTestWhileIdle(true);
}
public void execute(Command command) throws ExecutionException {
try {
Socket socket = this.connectionPool.borrowObject();
InputStream inputStream = socket.getInputStream();
command.request(inputStream);
command.response(socket.getOutputStream());
this.connectionPool.returnObject(socket);
} catch (Exception e) {
throw new ExecutionException(e);
} finally {
}
}
public void dispose() {
this.connectionPool.close();
}
//....以下省略
上面的代码可以看到一个Executor
接口,这是为了增强代码扩展性,抽象出来的接口
public interface Executor {
void execute(Command command) throws ExecutionException;
void dispose();
}
public interface Command {
void request(InputStream inputStream);
void response(OutputStream outputStream);
}
我们最终的目的是为了对外提供阻塞长连接服务,但socket对象池并非唯一实现方式。参考Command模式,我们只需要实现不同的executor就可以扩展不同的socket创建方式
/**
* 提供阻塞式socket服务
*/
public interface ServiceProvider {
void sendSimpleCommand();
}
public class ServiceProviderImpl implements ServiceProvider {
private Executor executor;
private void setExecutor(Executor executor) {
this.executor = executor;
}
public void sendSimpleCommand() {
try {
executor.execute(new Command() {
public void request(InputStream inputStream) {
}
public void response(OutputStream outputStream) {
}
});
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
网友评论