GenericObjectPool对象池实战

通常一个对象创建/销毁的时候非常耗时,我们不会频繁的创建销毁它,而是考虑复用。复用对象的一种做法就是对象池,将创建好的对象放入池中维护起来,下次再用的时候直接拿池中已经创建好的对象继续用

GenericObjectPool

GenericObjectPool是一个通用对象池框架,我们可以借助它实现一个健壮的对象池

维护一个对象池需要实现以下基本的功能:

  • 创建对象

  • 借出对象

  • 验证对象

  • 归还对象

  • 销毁对象

GenericObjectPool 需要通过构造器注入一个PooledObjectFactory对象,而PooledObjectFactory中提供了维护对象池的方法

public interface PooledObjectFactory {
    PooledObject makeObject() throws Exception;

    void destroyObject(PooledObject var1) throws Exception;

    boolean validateObject(PooledObject var1);

    void activateObject(PooledObject var1) throws Exception;

    void passivateObject(PooledObject var1) throws Exception;
}

以Socket连接池为例


    public class ConnectionFactory extends BasePooledObjectFactory {
        // 创建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 wrap(Socket socket) {
            return new DefaultPooledObject(socket);
        }

        /**
         * 能关的都给他关了
         * @param pooledObject
         * @throws Exception
         */
        public void destroyObject(PooledObject pooledObject) throws Exception {
            Socket socket = pooledObject.getObject();
            if (socket != null) {
                socket.getInputStream().close();
                socket.getOutputStream().close();
                socket.close();
            }
        }

        // 验证对象,Pool对象可以设置借出归还时候是否需要验证对象
        public boolean validateObject(PooledObject pooledObject) {
            Socket socket = pooledObject.getObject();
            return socket != null && !socket.isClosed() && socket.isConnected();
        }

        /**
         * 钝化归还对象,说白了就是对归还的对象清理
         * 清空输入流,避免因为上一个请求字节未读取完导致inputStream非空,对下一个产生影响
         * @param p
         * @throws Exception
         */
        @Override
        public void passivateObject(PooledObject 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 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();
        }
    }
}

你可能感兴趣的:(GenericObjectPool对象池实战)