001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.aop.target; 018 019import org.apache.commons.pool2.ObjectPool; 020import org.apache.commons.pool2.PooledObject; 021import org.apache.commons.pool2.PooledObjectFactory; 022import org.apache.commons.pool2.impl.DefaultPooledObject; 023import org.apache.commons.pool2.impl.GenericObjectPool; 024import org.apache.commons.pool2.impl.GenericObjectPoolConfig; 025 026import org.springframework.lang.Nullable; 027import org.springframework.util.Assert; 028 029/** 030 * {@link org.springframework.aop.TargetSource} implementation that holds 031 * objects in a configurable Apache Commons2 Pool. 032 * 033 * <p>By default, an instance of {@code GenericObjectPool} is created. 034 * Subclasses may change the type of {@code ObjectPool} used by 035 * overriding the {@code createObjectPool()} method. 036 * 037 * <p>Provides many configuration properties mirroring those of the Commons Pool 038 * {@code GenericObjectPool} class; these properties are passed to the 039 * {@code GenericObjectPool} during construction. If creating a subclass of this 040 * class to change the {@code ObjectPool} implementation type, pass in the values 041 * of configuration properties that are relevant to your chosen implementation. 042 * 043 * <p>The {@code testOnBorrow}, {@code testOnReturn} and {@code testWhileIdle} 044 * properties are explicitly not mirrored because the implementation of 045 * {@code PoolableObjectFactory} used by this class does not implement 046 * meaningful validation. All exposed Commons Pool properties use the 047 * corresponding Commons Pool defaults. 048 * 049 * <p>Compatible with Apache Commons Pool 2.4, as of Spring 4.2. 050 * 051 * @author Rod Johnson 052 * @author Rob Harrop 053 * @author Juergen Hoeller 054 * @author Stephane Nicoll 055 * @author Kazuki Shimizu 056 * @since 4.2 057 * @see GenericObjectPool 058 * @see #createObjectPool() 059 * @see #setMaxSize 060 * @see #setMaxIdle 061 * @see #setMinIdle 062 * @see #setMaxWait 063 * @see #setTimeBetweenEvictionRunsMillis 064 * @see #setMinEvictableIdleTimeMillis 065 */ 066@SuppressWarnings({"rawtypes", "unchecked", "serial"}) 067public class CommonsPool2TargetSource extends AbstractPoolingTargetSource implements PooledObjectFactory<Object> { 068 069 private int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE; 070 071 private int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE; 072 073 private long maxWait = GenericObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS; 074 075 private long timeBetweenEvictionRunsMillis = GenericObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; 076 077 private long minEvictableIdleTimeMillis = GenericObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; 078 079 private boolean blockWhenExhausted = GenericObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED; 080 081 /** 082 * The Apache Commons {@code ObjectPool} used to pool target objects. 083 */ 084 @Nullable 085 private ObjectPool pool; 086 087 088 /** 089 * Create a CommonsPoolTargetSource with default settings. 090 * Default maximum size of the pool is 8. 091 * @see #setMaxSize 092 * @see GenericObjectPoolConfig#setMaxTotal 093 */ 094 public CommonsPool2TargetSource() { 095 setMaxSize(GenericObjectPoolConfig.DEFAULT_MAX_TOTAL); 096 } 097 098 099 /** 100 * Set the maximum number of idle objects in the pool. 101 * Default is 8. 102 * @see GenericObjectPool#setMaxIdle 103 */ 104 public void setMaxIdle(int maxIdle) { 105 this.maxIdle = maxIdle; 106 } 107 108 /** 109 * Return the maximum number of idle objects in the pool. 110 */ 111 public int getMaxIdle() { 112 return this.maxIdle; 113 } 114 115 /** 116 * Set the minimum number of idle objects in the pool. 117 * Default is 0. 118 * @see GenericObjectPool#setMinIdle 119 */ 120 public void setMinIdle(int minIdle) { 121 this.minIdle = minIdle; 122 } 123 124 /** 125 * Return the minimum number of idle objects in the pool. 126 */ 127 public int getMinIdle() { 128 return this.minIdle; 129 } 130 131 /** 132 * Set the maximum waiting time for fetching an object from the pool. 133 * Default is -1, waiting forever. 134 * @see GenericObjectPool#setMaxWaitMillis 135 */ 136 public void setMaxWait(long maxWait) { 137 this.maxWait = maxWait; 138 } 139 140 /** 141 * Return the maximum waiting time for fetching an object from the pool. 142 */ 143 public long getMaxWait() { 144 return this.maxWait; 145 } 146 147 /** 148 * Set the time between eviction runs that check idle objects whether 149 * they have been idle for too long or have become invalid. 150 * Default is -1, not performing any eviction. 151 * @see GenericObjectPool#setTimeBetweenEvictionRunsMillis 152 */ 153 public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) { 154 this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; 155 } 156 157 /** 158 * Return the time between eviction runs that check idle objects. 159 */ 160 public long getTimeBetweenEvictionRunsMillis() { 161 return this.timeBetweenEvictionRunsMillis; 162 } 163 164 /** 165 * Set the minimum time that an idle object can sit in the pool before 166 * it becomes subject to eviction. Default is 1800000 (30 minutes). 167 * <p>Note that eviction runs need to be performed to take this 168 * setting into effect. 169 * @see #setTimeBetweenEvictionRunsMillis 170 * @see GenericObjectPool#setMinEvictableIdleTimeMillis 171 */ 172 public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) { 173 this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; 174 } 175 176 /** 177 * Return the minimum time that an idle object can sit in the pool. 178 */ 179 public long getMinEvictableIdleTimeMillis() { 180 return this.minEvictableIdleTimeMillis; 181 } 182 183 /** 184 * Set whether the call should bock when the pool is exhausted. 185 */ 186 public void setBlockWhenExhausted(boolean blockWhenExhausted) { 187 this.blockWhenExhausted = blockWhenExhausted; 188 } 189 190 /** 191 * Specify if the call should block when the pool is exhausted. 192 */ 193 public boolean isBlockWhenExhausted() { 194 return this.blockWhenExhausted; 195 } 196 197 198 /** 199 * Creates and holds an ObjectPool instance. 200 * @see #createObjectPool() 201 */ 202 @Override 203 protected final void createPool() { 204 logger.debug("Creating Commons object pool"); 205 this.pool = createObjectPool(); 206 } 207 208 /** 209 * Subclasses can override this if they want to return a specific Commons pool. 210 * They should apply any configuration properties to the pool here. 211 * <p>Default is a GenericObjectPool instance with the given pool size. 212 * @return an empty Commons {@code ObjectPool}. 213 * @see GenericObjectPool 214 * @see #setMaxSize 215 */ 216 protected ObjectPool createObjectPool() { 217 GenericObjectPoolConfig config = new GenericObjectPoolConfig(); 218 config.setMaxTotal(getMaxSize()); 219 config.setMaxIdle(getMaxIdle()); 220 config.setMinIdle(getMinIdle()); 221 config.setMaxWaitMillis(getMaxWait()); 222 config.setTimeBetweenEvictionRunsMillis(getTimeBetweenEvictionRunsMillis()); 223 config.setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis()); 224 config.setBlockWhenExhausted(isBlockWhenExhausted()); 225 return new GenericObjectPool(this, config); 226 } 227 228 229 /** 230 * Borrows an object from the {@code ObjectPool}. 231 */ 232 @Override 233 public Object getTarget() throws Exception { 234 Assert.state(this.pool != null, "No Commons ObjectPool available"); 235 return this.pool.borrowObject(); 236 } 237 238 /** 239 * Returns the specified object to the underlying {@code ObjectPool}. 240 */ 241 @Override 242 public void releaseTarget(Object target) throws Exception { 243 if (this.pool != null) { 244 this.pool.returnObject(target); 245 } 246 } 247 248 @Override 249 public int getActiveCount() throws UnsupportedOperationException { 250 return (this.pool != null ? this.pool.getNumActive() : 0); 251 } 252 253 @Override 254 public int getIdleCount() throws UnsupportedOperationException { 255 return (this.pool != null ? this.pool.getNumIdle() : 0); 256 } 257 258 259 /** 260 * Closes the underlying {@code ObjectPool} when destroying this object. 261 */ 262 @Override 263 public void destroy() throws Exception { 264 if (this.pool != null) { 265 logger.debug("Closing Commons ObjectPool"); 266 this.pool.close(); 267 } 268 } 269 270 271 //---------------------------------------------------------------------------- 272 // Implementation of org.apache.commons.pool2.PooledObjectFactory interface 273 //---------------------------------------------------------------------------- 274 275 @Override 276 public PooledObject<Object> makeObject() throws Exception { 277 return new DefaultPooledObject<>(newPrototypeInstance()); 278 } 279 280 @Override 281 public void destroyObject(PooledObject<Object> p) throws Exception { 282 destroyPrototypeInstance(p.getObject()); 283 } 284 285 @Override 286 public boolean validateObject(PooledObject<Object> p) { 287 return true; 288 } 289 290 @Override 291 public void activateObject(PooledObject<Object> p) throws Exception { 292 } 293 294 @Override 295 public void passivateObject(PooledObject<Object> p) throws Exception { 296 } 297 298}