【问题标题】:Create objects in GenericObjectPool在 GenericObjectPool 中创建对象
【发布时间】:2017-10-07 05:46:21
【问题描述】:

我正在研究GenericObjectPool,将Cipher 放入池中,以便可以重复使用。

GenericObjectPool<Cipher> pool;

CipherFactory factory = new CipherFactory(); 
this.pool = new GenericObjectPool<Cipher>(factory);
pool.setMaxTotal(10);
pool.setBlockWhenExhausted(true);
pool.setMaxWaitMillis(30 * 1000);

密码工厂

public class CipherFactory extends BasePooledObjectFactory<Cipher> {

    private boolean running = false;

    @Override
    public Cipher create() throws Exception {
        return Cipher.getInstance("DESede/CBC/NoPadding");
    }

    @Override
    public PooledObject<Cipher> wrap(Cipher arg0) {
        return new DefaultPooledObject<Cipher>(arg0);
    }

    @Override
    public boolean validateObject(PooledObject<Cipher> p) {
        //Ensures that the instance is safe to be returned by the pool
        return true;
    }

    @Override
    public void destroyObject(PooledObject<Cipher> p) {
        //Destroys an instance no longer needed by the pool. 
        System.out.println("destroying");
    }

    @Override
    public void activateObject(PooledObject<Cipher> p) throws Exception { //Reinitialize an instance to be returned by the pool

        setRunning(true);
    }

    @Override
    public void passivateObject(PooledObject<Cipher> p) throws Exception {   // reset the object after the object returns to the pool

        setRunning(false);
    }

    public void setRunning(boolean running) {

        this.running = running;
    }
//    
}

这就是我在 Example 类中实现 ObjectPool 的方式

public Key a(byte[] afyte) throws Exception {

        Cipher cipher = null;
        cipher = pool.borrowObject(); //get the object from the pool
        try {
            System.out.println("****************** After borrow ****************");
            printPool();
            cipher.init(Cipher.DECRYPT_MODE, mkkey, algParamSpec);
            byte[] de = cipher.doFinal(afyte);
            SecretKey mk = new SecretKeySpec(de, "DESede");
            return mk;
        } catch (Exception e) {
            pool.invalidateObject(cipher);
            cipher = null;
        } finally {
            if (null != cipher) {
                pool.returnObject(cipher);
                System.out.println("****************** After return ****************");
                printPool();
            }
        }
        return (Key) cipher;
    }

打印池

public void printPool() {
        System.out.println("Pool for cipher with instances DESede/CBC/NoPadding");
        System.out.println("Active [" + pool.getNumActive() + "]"); //Return the number of instances currently borrowed from this pool
        System.out.println("Idle [" + pool.getNumIdle() + "]"); //The number of instances currently idle in this pool
        System.out.println("Total Created [" + pool.getCreatedCount() + "]");      
    }

我在正确的道路上吗?是否可以增加池大小?

编辑

@http 的答案对我来说很好。但是如果我有另一种方法encryptECB(Key key, byte[] b),我该怎么写呢?

任何帮助将不胜感激!

【问题讨论】:

  • 池最多有 10 个,所以如果您不将它们返回到池中,那么该错误是预期的吗?如果您想在池用完时创建更多,那么您似乎根本不需要池,您可以在需要更多时继续创建它们。
  • 我走对了吗?
  • 如果您想继续使用池,请不要这样做。一个池应该具有有限数量的资源,例如在这种情况下您将其设置为 10。这意味着您不能超过 10,如果它们都很忙,您需要等待一个可用,然后再请求一个。另一方面,如果您不想等待,则意味着您没有限制,因此不需要池。
  • @tima 我看到了这个example,如果池大小为空,它可以增加池大小。但不确定在我的情况下是否可以这样做。
  • 你可以试试,我认为它是旧版本的 apache-commons-pool (~2012)。您也可以尝试像这样设置您的pool.setMaxTotal(-1);,这应该允许您需要的任意数量的对象。它并没有真正增加它。

标签: java object generics apache-commons pool


【解决方案1】:

你在正确的轨道上。在构造 GenericObjectPool 时,您可以使用接受 GenericObjectPoolConfig 对象的构造函数,该对象包含对象池的所有配置值。下面的示例将让您的池在耗尽之前增长到 20 个连接...

GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMinIdle(2);
config.setMaxIdle(5);
config.setMaxTotal(20);

GenericObjectPool<Cipher> pool;
CipherFactory factory = new CipherFactory(); 
this.pool = new GenericObjectPool<Cipher>(factory, config);

GenericeObjectPoolConfig 还有一个 setBlockWhenExhausted 方法来指定池达到 maxTotal 连接数时的行为。详情请见https://commons.apache.org/proper/commons-pool/apidocs/org/apache/commons/pool2/impl/BaseObjectPoolConfig.html#setBlockWhenExhausted-boolean-

我在使用公共池时实现的一种模式是创建 2 个接口,一个用于您的池对象,一个用于您的工厂...

public interface PooledCipher extends java.io.Closeable {
    byte[] doFinal(byte[] bytes) throws Exception;
    SecretKeySpec getSecretKeySpec(byte[] bytes) throws Exception;
}

public interface CipherFactory {
    PooledCipher getCipher() throws Exception;        
    void close();
}

CipherFactory 实现...

public class CipherFactoryImpl extends BasePooledObjectFactory<PooledCipher> 
    implements CipherFactory {

    private final GenericObjectPoolConfig config;
    private final GenericObjectPool<PooledCipher> pool;
    private final String transformation;
    private final int opmode;
    private final Key key;
    private final AlgorithmParameters params;
    private final String secretKeySpecAlgorithm;

    public CipherFactoryImpl(GenericObjectPoolConfig config, String transformation, int opmode, Key key, AlgorithmParameters params, String secretKeySpecAlgorithm) {
        this.config = config;
        this.pool = new GenericObjectPool<PooledCipher>(this, config);
        this.transformation = transformation;
        this.opmode = opmode;
        this.key = key;
        this.params = params;       
        this.secretKeySpecAlgorithm = secretKeySpecAlgorithm
    }

    @Override
    public PooledCipher create() throws Exception {
        return new PooledCipherImpl(pool, transformation, opmode, key, params, secretKeySpecAlgorithm);
    }

    @Override
    public PooledCipher getCipher() throws Exception {
        return pool.borrowObject();
    }

    @Override
    public void destroyObject(PooledObject<PooledCipher> p) throws Exception {
        try {
            PooledCipherImpl cipherImpl = (PooledCipherImpl)p.getObject();
            // do whatever you need with cipherImpl to destroy it
        } finally {
            super.destroyObject(p);
        }
    }

    @Override
    public void close() {
        pool.close();
    }

    @Override
    public PooledObject<PooledCipher> wrap(PooledCipher cipher) {
        return new DefaultPooledObject<PooledCipher>(cipher);
    }
}

PooledCipher 实现...

public class PooledCipherImpl implements PooledCipher {
    private final ObjectPool<PooledCipher> pool;
    private final Cipher cipher;
    private final String secretKeySpecAlgorithm;
    private boolean destroyOnClose = false;

    public PooledCipherImpl(ObjectPool<PooledCipher> pool, String transformation, int opmode, Key key, AlgorithmParameters params, String secretKeySpecAlgorithm) {
        this.pool = pool;
        this.cipher = Cipher.getInstance(transformation);
        this.cipher.init(opmode, key, params);
        this.secretKeySpecAlgorithm = secretKeySpecAlgorithm;
    }

    @Override
    public byte[] doFinal(byte[] bytes) throws Exception {
        try {
            return cipher.doFinal(bytes);
        } catch (Exception e) {
           destroyOnClose = true;
           throw e;
        }
    }

    @Override
    public SecretKeySpec getSecretKeySpec(byte[] bytes) {
        return new SecretKeySpec(doFinal(bytes), secretKeySpecAlgorithm);
    }

    @Override
    public void close() throws IOException {
        try {
            if (destroyOnClose) {
                pool.destroyObject(this);
            } else {
                pool.returnObject(this);
            }
        } catch (Exception e) {
            throw new IOException(e);
        }
    }
}

然后你像这样构造你的 CipherFactory...

String transformation = "DESede/CBC/NoPadding";
String secretKeySpecAlgorithm = "DESede";
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
// set up the poolConfig here
poolConfig.setMaxTotal(20);
CipherFactory cipherFactory = new CipherFactoryImpl(poolConfig, transformation, Cipher.DECRYPT_MODE, mkkey, algParamSpec, secretKeySpecAlgorithm);

然后像这样使用它......

public Key unwrapKey(byte[] tmkByte) throws Exception {
    try (PooledCipher cipher = cipherFactory.getCipher()) {
        return cipher.getSecretKeySpec(tmkByte);
    }
}

您还可以重用 PooledCipher 和 CipherFactory 接口来创建其他实现,例如 JCA。

【讨论】:

  • 这如何让池增长?它只是增加了初始大小
  • 我注意到有一些使用GenericObjectPoolConfig的例子。为什么需要它,因为我可以使用pool.setMaxTotal(20); 而不是config.setMaxTotal(20);。实际上有什么区别?
  • 让我先试试
  • 我使用 GenericObjectPoolConfig 因为我通常创建该对象并根据配置文件设置值。在我的例子中,我使用的是 spring,所以我可以创建一个 GenericObjectPoolConfig bean 并从属性文件初始化所有属性。
  • 嗨托尼,我已经编辑了我的答案,使其更接近可编译的解决方案,并演示如何销毁对象。希望这更清楚。
猜你喜欢
  • 2019-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多