2017-05-09 31 views
11

Przeprowadzam badania na GenericObjectPool, umieszczając Cipher w puli, aby można było ponownie użyć.Tworzenie obiektów w GenericObjectPool

GenericObjectPool<Cipher> pool; 

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

CipherFactory

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; 
    } 
//  
} 

ten sposób zaimplementować ObjectPool w moim przykładu klasy

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; 
    } 

printPool

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() + "]");  
    } 

Czy jestem na dobrej drodze? Czy można zwiększyć rozmiar basenu?

Edit

Odpowiedź z @http działa dobrze dla mnie. Ale jeśli mam inną metodę encryptECB(Key key, byte[] b), jak mam pisać?

Każda pomoc zostanie doceniona!

+0

Pula może mieć maksymalnie 10, więc jeśli nie zwrócisz ich do puli, ten błąd jest oczekiwany? A jeśli chcesz utworzyć więcej, jeśli pula się kończy, wydaje się, że w ogóle nie potrzebujesz basenu, możesz po prostu tworzyć je, gdy potrzebujesz więcej. – tima

+0

Czy jestem na dobrej drodze? – Tony

+0

Nie, jeśli chcesz nadal korzystać z puli. Pula powinna mieć ograniczoną liczbę zasobów, na przykład w tym przypadku została utworzona 10.Oznacza to, że nie możesz przekroczyć 10, a jeśli wszystkie są zajęte, musisz poczekać, aż stanie się dostępny, zanim zażądasz. Z drugiej strony, jeśli nie chcesz czekać, oznacza to, że nie możesz mieć limitu i dlatego nie potrzebujesz puli. – tima

Odpowiedz

6

Jesteś na dobrej drodze. Podczas konstruowania GenericObjectPool można użyć konstruktora, który akceptuje obiekt GenericObjectPoolConfig, który zawiera wszystkie wartości konfiguracyjne dla puli obiektów. Poniższy przykład pozwoli pula wzrośnie do 20 połączeń, zanim został wyczerpany ...

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 posiada również setBlockWhenExhausted metodę, aby określić zachowanie, gdy pula osiągnęła maxTotal połączeń. Aby uzyskać szczegółowe informacje, patrz: https://commons.apache.org/proper/commons-pool/apidocs/org/apache/commons/pool2/impl/BaseObjectPoolConfig.html#setBlockWhenExhausted-boolean-.

Wzór zaimplementować przy użyciu commons basen jest stworzenie 2 interfejsy dla swojego obiektu zbiorczej i jeden dla swojej fabryki ...

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(); 
} 

realizacja 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); 
    } 
} 

Implementacja 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); 
     } 
    } 
} 

Następnie skonstruuj swój CipherFactory w ten sposób .. .

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); 

i używać go tak ...

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

Ponadto można ponownie wykorzystać interfejsy PooledCipher i CipherFactory tworzyć inne realizacje, takie jak JCA.

+1

Jak to się stało, że basen rośnie? Po prostu zwiększa początkowy rozmiar. – tima

+0

Zauważyłem, że istnieje przykład użycia 'GenericObjectPoolConfig'. Po co to robić, ponieważ mogę używać 'pool.setMaxTotal (20);' zamiast 'config.setMaxTotal (20);'. Na czym właściwie polega różnica? – Tony

+0

Pozwól mi najpierw spróbować – Tony

Powiązane problemy