diff --git a/build.gradle b/build.gradle index 316a0f7c70e..395cea4c298 100644 --- a/build.gradle +++ b/build.gradle @@ -405,6 +405,7 @@ project("spring-aop") { compile("aopalliance:aopalliance:1.0") optional("org.aspectj:aspectjweaver:${aspectjVersion}") optional("commons-pool:commons-pool:1.6") + optional("org.apache.commons:commons-pool2:2.2") optional("com.jamonapi:jamon:2.79") } } @@ -463,6 +464,7 @@ project("spring-context") { optional("org.jruby:jruby:1.7.17") testCompile("javax.inject:javax.inject-tck:1") testCompile("commons-dbcp:commons-dbcp:1.4") + testCompile("org.apache.commons:commons-pool2:2.2") testCompile("org.slf4j:slf4j-api:${slf4jVersion}") } diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/AbstractSingletonProxyFactoryBean.java b/spring-aop/src/main/java/org/springframework/aop/framework/AbstractSingletonProxyFactoryBean.java index 261d1cab604..f24b22df596 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/AbstractSingletonProxyFactoryBean.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/AbstractSingletonProxyFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -66,7 +66,7 @@ public abstract class AbstractSingletonProxyFactoryBean extends ProxyConfig * @see org.springframework.aop.target.SingletonTargetSource * @see org.springframework.aop.target.LazyInitTargetSource * @see org.springframework.aop.target.PrototypeTargetSource - * @see org.springframework.aop.target.CommonsPoolTargetSource + * @see org.springframework.aop.target.CommonsPool2TargetSource */ public void setTarget(Object target) { this.target = target; diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/target/QuickTargetSourceCreator.java b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/target/QuickTargetSourceCreator.java index dc37b8099f0..46d6fdbd607 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/target/QuickTargetSourceCreator.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/target/QuickTargetSourceCreator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,19 +17,20 @@ package org.springframework.aop.framework.autoproxy.target; import org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource; -import org.springframework.aop.target.CommonsPoolTargetSource; +import org.springframework.aop.target.CommonsPool2TargetSource; import org.springframework.aop.target.PrototypeTargetSource; import org.springframework.aop.target.ThreadLocalTargetSource; /** * Convenient TargetSourceCreator using bean name prefixes to create one of three * well-known TargetSource types: - *
  • : CommonsPoolTargetSource + *
  • : CommonsPool2TargetSource *
  • % ThreadLocalTargetSource *
  • ! PrototypeTargetSource * * @author Rod Johnson - * @see org.springframework.aop.target.CommonsPoolTargetSource + * @author Stephane Nicoll + * @see org.springframework.aop.target.CommonsPool2TargetSource * @see org.springframework.aop.target.ThreadLocalTargetSource * @see org.springframework.aop.target.PrototypeTargetSource */ @@ -44,7 +45,7 @@ public class QuickTargetSourceCreator extends AbstractBeanFactoryBasedTargetSour Class beanClass, String beanName) { if (beanName.startsWith(PREFIX_COMMONS_POOL)) { - CommonsPoolTargetSource cpts = new CommonsPoolTargetSource(); + CommonsPool2TargetSource cpts = new CommonsPool2TargetSource(); cpts.setMaxSize(25); return cpts; } diff --git a/spring-aop/src/main/java/org/springframework/aop/target/AbstractBeanFactoryBasedTargetSource.java b/spring-aop/src/main/java/org/springframework/aop/target/AbstractBeanFactoryBasedTargetSource.java index b21cc4ba1a0..56f618171c6 100644 --- a/spring-aop/src/main/java/org/springframework/aop/target/AbstractBeanFactoryBasedTargetSource.java +++ b/spring-aop/src/main/java/org/springframework/aop/target/AbstractBeanFactoryBasedTargetSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,7 +45,7 @@ import org.springframework.util.ObjectUtils; * @see LazyInitTargetSource * @see PrototypeTargetSource * @see ThreadLocalTargetSource - * @see CommonsPoolTargetSource + * @see CommonsPool2TargetSource */ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSource, BeanFactoryAware, Serializable { diff --git a/spring-aop/src/main/java/org/springframework/aop/target/AbstractPoolingTargetSource.java b/spring-aop/src/main/java/org/springframework/aop/target/AbstractPoolingTargetSource.java index 63d8d6d2066..897c05aa37b 100644 --- a/spring-aop/src/main/java/org/springframework/aop/target/AbstractPoolingTargetSource.java +++ b/spring-aop/src/main/java/org/springframework/aop/target/AbstractPoolingTargetSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ import org.springframework.beans.factory.DisposableBean; * implementations which maintain a pool of target instances, acquiring and * releasing a target object from the pool for each method invocation. * This abstract base class is independent of concrete pooling technology; - * see the subclass {@link CommonsPoolTargetSource} for a concrete example. + * see the subclass {@link CommonsPool2TargetSource} for a concrete example. * *

    Subclasses must implement the {@link #getTarget} and * {@link #releaseTarget} methods based on their chosen object pool. diff --git a/spring-aop/src/main/java/org/springframework/aop/target/AbstractPrototypeBasedTargetSource.java b/spring-aop/src/main/java/org/springframework/aop/target/AbstractPrototypeBasedTargetSource.java index 24e0286e97f..415d0e57e12 100644 --- a/spring-aop/src/main/java/org/springframework/aop/target/AbstractPrototypeBasedTargetSource.java +++ b/spring-aop/src/main/java/org/springframework/aop/target/AbstractPrototypeBasedTargetSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,7 +41,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory; * @see org.springframework.beans.factory.BeanFactory#getBean * @see PrototypeTargetSource * @see ThreadLocalTargetSource - * @see CommonsPoolTargetSource + * @see CommonsPool2TargetSource */ @SuppressWarnings("serial") public abstract class AbstractPrototypeBasedTargetSource extends AbstractBeanFactoryBasedTargetSource { diff --git a/spring-aop/src/main/java/org/springframework/aop/target/CommonsPool2TargetSource.java b/spring-aop/src/main/java/org/springframework/aop/target/CommonsPool2TargetSource.java new file mode 100644 index 00000000000..4cc34dcf65a --- /dev/null +++ b/spring-aop/src/main/java/org/springframework/aop/target/CommonsPool2TargetSource.java @@ -0,0 +1,345 @@ +/* + * Copyright 2002-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.target; + +import org.apache.commons.pool2.ObjectPool; +import org.apache.commons.pool2.PooledObject; +import org.apache.commons.pool2.PooledObjectFactory; +import org.apache.commons.pool2.impl.DefaultPooledObject; +import org.apache.commons.pool2.impl.GenericObjectPool; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; + +/** + * {@link org.springframework.aop.TargetSource} implementation that holds + * objects in a configurable Apache Commons2 Pool. + * + *

    By default, an instance of {@code GenericObjectPool} is created. + * Subclasses may change the type of {@code ObjectPool} used by + * overriding the {@code createObjectPool()} method. + * + *

    Provides many configuration properties mirroring those of the Commons Pool + * {@code GenericObjectPool} class; these properties are passed to the + * {@code GenericObjectPool} during construction. If creating a subclass of this + * class to change the {@code ObjectPool} implementation type, pass in the values + * of configuration properties that are relevant to your chosen implementation. + * + *

    The {@code testOnBorrow}, {@code testOnReturn} and {@code testWhileIdle} + * properties are explicitly not mirrored because the implementation of + * {@code PoolableObjectFactory} used by this class does not implement + * meaningful validation. All exposed Commons Pool properties use the + * corresponding Commons Pool defaults. + * + *

    Commons Pool 2.x uses object equality while Commons Pool 1.x used identity + * equality. This clearly means that Commons Pool 2 behaves differently if several + * instances having the same identity according to their {@link Object#equals(Object)} + * method are managed in the same pool. To provide a smooth upgrade, a + * backward-compatible pool is created by default; use {@link #setUseObjectEquality(boolean)} + * if you need the standard Commons Pool 2.x behavior. + * + *

    Compatible with Apache Commons Pool 2.2 + * + * @author Rod Johnson + * @author Rob Harrop + * @author Juergen Hoeller + * @author Stephane Nicoll + * @since 4.2 + * @see GenericObjectPool + * @see #createObjectPool() + * @see #setMaxSize + * @see #setMaxIdle + * @see #setMinIdle + * @see #setMaxWait + * @see #setTimeBetweenEvictionRunsMillis + * @see #setMinEvictableIdleTimeMillis + */ +@SuppressWarnings({"rawtypes", "unchecked", "serial"}) +public class CommonsPool2TargetSource extends AbstractPoolingTargetSource implements PooledObjectFactory { + + private int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE; + + private int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE; + + private long maxWait = GenericObjectPoolConfig.DEFAULT_MAX_TOTAL; + + private long timeBetweenEvictionRunsMillis = GenericObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; + + private long minEvictableIdleTimeMillis = GenericObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; + + private boolean blockWhenExhausted = GenericObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED; + + private boolean useObjectEquality; + + /** + * The Jakarta Commons {@code ObjectPool} used to pool target objects + */ + private ObjectPool pool; + + + /** + * Create a CommonsPoolTargetSource with default settings. + * Default maximum size of the pool is 8. + * @see #setMaxSize + * @see GenericObjectPoolConfig#setMaxTotal + */ + public CommonsPool2TargetSource() { + setMaxSize(GenericObjectPoolConfig.DEFAULT_MAX_TOTAL); + } + + /** + * Set the maximum number of idle objects in the pool. + * Default is 8. + * @see GenericObjectPool#setMaxIdle + */ + public void setMaxIdle(int maxIdle) { + this.maxIdle = maxIdle; + } + + /** + * Return the maximum number of idle objects in the pool. + */ + public int getMaxIdle() { + return this.maxIdle; + } + + /** + * Set the minimum number of idle objects in the pool. + * Default is 0. + * @see GenericObjectPool#setMinIdle + */ + public void setMinIdle(int minIdle) { + this.minIdle = minIdle; + } + + /** + * Return the minimum number of idle objects in the pool. + */ + public int getMinIdle() { + return this.minIdle; + } + + /** + * Set the maximum waiting time for fetching an object from the pool. + * Default is -1, waiting forever. + * @see GenericObjectPool#setMaxTotal + */ + public void setMaxWait(long maxWait) { + this.maxWait = maxWait; + } + + /** + * Return the maximum waiting time for fetching an object from the pool. + */ + public long getMaxWait() { + return this.maxWait; + } + + /** + * Set the time between eviction runs that check idle objects whether + * they have been idle for too long or have become invalid. + * Default is -1, not performing any eviction. + * @see GenericObjectPool#setTimeBetweenEvictionRunsMillis + */ + public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) { + this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; + } + + /** + * Return the time between eviction runs that check idle objects. + */ + public long getTimeBetweenEvictionRunsMillis() { + return this.timeBetweenEvictionRunsMillis; + } + + /** + * Set the minimum time that an idle object can sit in the pool before + * it becomes subject to eviction. Default is 1800000 (30 minutes). + *

    Note that eviction runs need to be performed to take this + * setting into effect. + * @see #setTimeBetweenEvictionRunsMillis + * @see GenericObjectPool#setMinEvictableIdleTimeMillis + */ + public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) { + this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; + } + + /** + * Return the minimum time that an idle object can sit in the pool. + */ + public long getMinEvictableIdleTimeMillis() { + return this.minEvictableIdleTimeMillis; + } + + /** + * Set whether the call should bock when the pool is exhausted. + */ + public void setBlockWhenExhausted(boolean blockWhenExhausted) { + this.blockWhenExhausted = blockWhenExhausted; + } + + /** + * Specify if the call should block when the pool is exhausted. + */ + public boolean isBlockWhenExhausted() { + return blockWhenExhausted; + } + + /** + * Set if the pool should use object equality. Commons Pool 1.x has no specific requirement in + * that regard and allows two distinct instances being equal to be put in the same pool. However, + * this behavior has changed with commons pool 2. To preserve backward compatibility, the pool + * is configured to use reference equality ({@code false}. + */ + public void setUseObjectEquality(boolean useObjectEquality) { + this.useObjectEquality = useObjectEquality; + } + + /** + * Specify if the pool should use object equality. Return {@code false} if it should use + * reference equality (as it was the case for Commons Pool 1.x) + */ + public boolean isUseObjectEquality() { + return useObjectEquality; + } + + /** + * Creates and holds an ObjectPool instance. + * @see #createObjectPool() + */ + @Override + protected final void createPool() { + logger.debug("Creating Commons object pool"); + this.pool = createObjectPool(); + } + + /** + * Subclasses can override this if they want to return a specific Commons pool. + * They should apply any configuration properties to the pool here. + *

    Default is a GenericObjectPool instance with the given pool size. + * @return an empty Commons {@code ObjectPool}. + * @see GenericObjectPool + * @see #setMaxSize + */ + protected ObjectPool createObjectPool() { + GenericObjectPoolConfig config = new GenericObjectPoolConfig(); + config.setMaxTotal(getMaxSize()); + config.setMaxIdle(getMaxIdle()); + config.setMinIdle(getMinIdle()); + config.setMaxWaitMillis(getMaxWait()); + config.setTimeBetweenEvictionRunsMillis(getTimeBetweenEvictionRunsMillis()); + config.setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis()); + config.setBlockWhenExhausted(isBlockWhenExhausted()); + return new GenericObjectPool(this, config); + } + + + /** + * Borrow an object from the {@code ObjectPool}. + */ + @Override + public Object getTarget() throws Exception { + Object o = this.pool.borrowObject(); + return (isUseObjectEquality() ? o : ((IdentityWrapper)o).target); + } + + /** + * Returns the specified object to the underlying {@code ObjectPool}. + */ + @Override + public void releaseTarget(Object target) throws Exception { + Object value = (isUseObjectEquality() ? target : new IdentityWrapper(target)); + this.pool.returnObject(value); + } + + @Override + public int getActiveCount() throws UnsupportedOperationException { + return this.pool.getNumActive(); + } + + @Override + public int getIdleCount() throws UnsupportedOperationException { + return this.pool.getNumIdle(); + } + + + /** + * Closes the underlying {@code ObjectPool} when destroying this object. + */ + @Override + public void destroy() throws Exception { + logger.debug("Closing Commons ObjectPool"); + this.pool.close(); + } + + + //---------------------------------------------------------------------------- + // Implementation of org.apache.commons.pool2.PooledObjectFactory interface + //---------------------------------------------------------------------------- + + @Override + public PooledObject makeObject() throws Exception { + Object target = newPrototypeInstance(); + Object poolValue = (isUseObjectEquality() ? target : new IdentityWrapper(target)); + return new DefaultPooledObject(poolValue); + } + + @Override + public void destroyObject(PooledObject p) throws Exception { + destroyPrototypeInstance(p.getObject()); + } + + @Override + public boolean validateObject(PooledObject p) { + return true; + } + + @Override + public void activateObject(PooledObject p) throws Exception { + } + + @Override + public void passivateObject(PooledObject p) throws Exception { + } + + + /** + * Wraps the target type in the pool to restore the behavior of commons-pool 1.x. + */ + private static class IdentityWrapper { + private final Object target; + + public IdentityWrapper(Object target) { + this.target = target; + } + + @Override + public int hashCode() { + return System.identityHashCode(this.target); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + IdentityWrapper that = (IdentityWrapper) o; + + return !(target != null ? !(target == that.target) : that.target != null); + } + + } + +} diff --git a/spring-aop/src/main/java/org/springframework/aop/target/CommonsPoolTargetSource.java b/spring-aop/src/main/java/org/springframework/aop/target/CommonsPoolTargetSource.java index 5392d3c2997..eb1a98b3b1f 100644 --- a/spring-aop/src/main/java/org/springframework/aop/target/CommonsPoolTargetSource.java +++ b/spring-aop/src/main/java/org/springframework/aop/target/CommonsPoolTargetSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,8 +58,10 @@ import org.springframework.core.Constants; * @see #setMaxWait * @see #setTimeBetweenEvictionRunsMillis * @see #setMinEvictableIdleTimeMillis + * @deprecated as of Spring 4.2, in favor of {@link CommonsPool2TargetSource} */ @SuppressWarnings({"rawtypes", "unchecked", "serial"}) +@Deprecated public class CommonsPoolTargetSource extends AbstractPoolingTargetSource implements PoolableObjectFactory { private static final Constants constants = new Constants(GenericObjectPool.class); diff --git a/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorTests.java b/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorTests.java index dd8f06c09f1..5c7dfce742d 100644 --- a/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorTests.java +++ b/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ import org.springframework.aop.framework.Advised; import org.springframework.aop.framework.autoproxy.target.AbstractBeanFactoryBasedTargetSourceCreator; import org.springframework.aop.support.AopUtils; import org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource; -import org.springframework.aop.target.CommonsPoolTargetSource; +import org.springframework.aop.target.CommonsPool2TargetSource; import org.springframework.aop.target.LazyInitTargetSource; import org.springframework.aop.target.PrototypeTargetSource; import org.springframework.aop.target.ThreadLocalTargetSource; @@ -154,7 +154,7 @@ public final class AdvisorAutoProxyCreatorTests { test = (ITestBean) bf.getBean(":test"); assertTrue(AopUtils.isAopProxy(test)); Advised advised = (Advised) test; - assertTrue(advised.getTargetSource() instanceof CommonsPoolTargetSource); + assertTrue(advised.getTargetSource() instanceof CommonsPool2TargetSource); assertEquals("Rod", test.getName()); // Check that references survived pooling assertEquals("Kerry", test.getSpouse().getName()); diff --git a/spring-context/src/test/java/org/springframework/aop/target/CommonsPoolTargetSourceTests-context.xml b/spring-context/src/test/java/org/springframework/aop/target/CommonsPool2TargetSourceTests-context.xml similarity index 95% rename from spring-context/src/test/java/org/springframework/aop/target/CommonsPoolTargetSourceTests-context.xml rename to spring-context/src/test/java/org/springframework/aop/target/CommonsPool2TargetSourceTests-context.xml index 298ae976fee..0ce62590013 100644 --- a/spring-context/src/test/java/org/springframework/aop/target/CommonsPoolTargetSourceTests-context.xml +++ b/spring-context/src/test/java/org/springframework/aop/target/CommonsPool2TargetSourceTests-context.xml @@ -7,7 +7,7 @@ 10 - + prototypeTest 25 @@ -44,7 +44,7 @@ - + prototypePerson 10 @@ -57,7 +57,7 @@ - + diff --git a/spring-context/src/test/java/org/springframework/aop/target/CommonsPoolTargetSourceTests.java b/spring-context/src/test/java/org/springframework/aop/target/CommonsPool2TargetSourceTests.java similarity index 76% rename from spring-context/src/test/java/org/springframework/aop/target/CommonsPoolTargetSourceTests.java rename to spring-context/src/test/java/org/springframework/aop/target/CommonsPool2TargetSourceTests.java index dec2e918ed0..6dcf240e641 100644 --- a/spring-context/src/test/java/org/springframework/aop/target/CommonsPoolTargetSourceTests.java +++ b/spring-context/src/test/java/org/springframework/aop/target/CommonsPool2TargetSourceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,10 +18,11 @@ package org.springframework.aop.target; import java.util.NoSuchElementException; -import org.apache.commons.pool.impl.GenericObjectPool; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.springframework.aop.framework.Advised; import org.springframework.beans.factory.support.DefaultListableBeanFactory; @@ -43,8 +44,12 @@ import static org.junit.Assert.*; * @author Rod Johnson * @author Rob Harrop * @author Chris Beams + * @author Stephane Nicoll */ -public class CommonsPoolTargetSourceTests { +public class CommonsPool2TargetSourceTests { + + @Rule + public final ExpectedException thrown = ExpectedException.none(); /** * Initial count value set in bean factory XML @@ -109,7 +114,7 @@ public class CommonsPoolTargetSourceTests { @Test public void testTargetSourceSerializableWithoutConfigMixin() throws Exception { - CommonsPoolTargetSource cpts = (CommonsPoolTargetSource) beanFactory.getBean("personPoolTargetSource"); + CommonsPool2TargetSource cpts = (CommonsPool2TargetSource) beanFactory.getBean("personPoolTargetSource"); SingletonTargetSource serialized = (SingletonTargetSource) SerializationTestUtils.serializeAndDeserialize(cpts); assertTrue(serialized.getTarget() instanceof Person); @@ -121,7 +126,7 @@ public class CommonsPoolTargetSourceTests { Person pooled = (Person) beanFactory.getBean("pooledPerson"); //System.out.println(((Advised) pooled).toProxyConfigString()); - assertTrue(((Advised) pooled).getTargetSource() instanceof CommonsPoolTargetSource); + assertTrue(((Advised) pooled).getTargetSource() instanceof CommonsPool2TargetSource); //((Advised) pooled).setTargetSource(new SingletonTargetSource(new SerializablePerson())); Person serialized = (Person) SerializationTestUtils.serializeAndDeserialize(pooled); @@ -134,7 +139,7 @@ public class CommonsPoolTargetSourceTests { public void testHitMaxSize() throws Exception { int maxSize = 10; - CommonsPoolTargetSource targetSource = new CommonsPoolTargetSource(); + CommonsPool2TargetSource targetSource = new CommonsPool2TargetSource(); targetSource.setMaxSize(maxSize); targetSource.setMaxWait(1); prepareTargetSource(targetSource); @@ -169,7 +174,7 @@ public class CommonsPoolTargetSourceTests { @Test public void testHitMaxSizeLoadedFromContext() throws Exception { Advised person = (Advised) beanFactory.getBean("maxSizePooledPerson"); - CommonsPoolTargetSource targetSource = (CommonsPoolTargetSource) person.getTargetSource(); + CommonsPool2TargetSource targetSource = (CommonsPool2TargetSource) person.getTargetSource(); int maxSize = targetSource.getMaxSize(); Object[] pooledInstances = new Object[maxSize]; @@ -195,18 +200,54 @@ public class CommonsPoolTargetSourceTests { // release all objects for (int i = 0; i < pooledInstances.length; i++) { + System.out.println(i); targetSource.releaseTarget(pooledInstances[i]); } } @Test public void testSetWhenExhaustedAction() { - CommonsPoolTargetSource targetSource = new CommonsPoolTargetSource(); - targetSource.setWhenExhaustedActionName("WHEN_EXHAUSTED_BLOCK"); - assertEquals(GenericObjectPool.WHEN_EXHAUSTED_BLOCK, targetSource.getWhenExhaustedAction()); + CommonsPool2TargetSource targetSource = new CommonsPool2TargetSource(); + targetSource.setBlockWhenExhausted(true); + assertEquals(true, targetSource.isBlockWhenExhausted()); + } + + @Test + public void referenceIdentityByDefault() throws Exception { + CommonsPool2TargetSource targetSource = new CommonsPool2TargetSource(); + targetSource.setMaxWait(1); + prepareTargetSource(targetSource); + + Object first = targetSource.getTarget(); + Object second = targetSource.getTarget(); + assertTrue(first instanceof SerializablePerson); + assertTrue(second instanceof SerializablePerson); + assertEquals(first, second); + + targetSource.releaseTarget(first); + targetSource.releaseTarget(second); + } + + @Test + public void objectIdentityReleaseWithSeveralEqualInstances() throws Exception{ + CommonsPool2TargetSource targetSource = new CommonsPool2TargetSource(); + targetSource.setUseObjectEquality(true); + targetSource.setMaxWait(1); + prepareTargetSource(targetSource); + + Object first = targetSource.getTarget(); + Object second = targetSource.getTarget(); + assertTrue(first instanceof SerializablePerson); + assertTrue(second instanceof SerializablePerson); + assertEquals(first, second); + + targetSource.releaseTarget(first); + thrown.expect(IllegalStateException.class); // Only one object in pool + targetSource.releaseTarget(second); + } - private void prepareTargetSource(CommonsPoolTargetSource targetSource) { + private void prepareTargetSource(CommonsPool2TargetSource targetSource) { String beanName = "target"; StaticApplicationContext applicationContext = new StaticApplicationContext(); diff --git a/src/asciidoc/appendix.adoc b/src/asciidoc/appendix.adoc index ae0d0e3739a..01df7e9a764 100644 --- a/src/asciidoc/appendix.adoc +++ b/src/asciidoc/appendix.adoc @@ -2049,12 +2049,17 @@ A crucial difference between Spring pooling and SLSB pooling is that Spring pool be applied to any POJO. As with Spring in general, this service can be applied in a non-invasive way. -Spring provides out-of-the-box support for Jakarta Commons Pool 1.3, which provides a +Spring provides out-of-the-box support for Commons Pool 2.2, which provides a fairly efficient pooling implementation. You'll need the commons-pool Jar on your application's classpath to use this feature. It's also possible to subclass `org.springframework.aop.target.AbstractPoolingTargetSource` to support any other pooling API. +[NOTE] +==== +Commons Pool 1.5+ is also supported but deprecated as of Spring Framework 4.2. +==== + Sample configuration is shown below: [source,xml,indent=0] @@ -2064,7 +2069,7 @@ Sample configuration is shown below: ... properties omitted - + diff --git a/src/asciidoc/index.adoc b/src/asciidoc/index.adoc index 9e3626c91ba..f8be201867a 100644 --- a/src/asciidoc/index.adoc +++ b/src/asciidoc/index.adoc @@ -18305,12 +18305,18 @@ A crucial difference between Spring pooling and SLSB pooling is that Spring pool be applied to any POJO. As with Spring in general, this service can be applied in a non-invasive way. -Spring provides out-of-the-box support for Jakarta Commons Pool 1.3, which provides a +Spring provides out-of-the-box support for Commons Pool 2.2, which provides a fairly efficient pooling implementation. You'll need the commons-pool Jar on your application's classpath to use this feature. It's also possible to subclass `org.springframework.aop.target.AbstractPoolingTargetSource` to support any other pooling API. +[NOTE] +==== +Commons Pool 1.5+ is also supported but deprecated as of Spring Framework 4.2. +==== + + Sample configuration is shown below: [source,xml,indent=0] @@ -18321,7 +18327,7 @@ Sample configuration is shown below: ... properties omitted - +