diff --git a/.gitignore b/.gitignore
index d713eae13a511a57c2fdc3ac266f8b06ac6e8d14..b69cb116254113448412d4e8ac32b0c2f9dc150b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,7 +22,6 @@ classes/
buildSrc/build
/spring-*/build
/src/asciidoc/build
-target/
# Projects not in this branch
integration-tests/
diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/target/AbstractBeanFactoryBasedTargetSourceCreator.java b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/target/AbstractBeanFactoryBasedTargetSourceCreator.java
new file mode 100644
index 0000000000000000000000000000000000000000..4fd173f2893eb34fd1b24a20716a168936a48318
--- /dev/null
+++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/target/AbstractBeanFactoryBasedTargetSourceCreator.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2002-2018 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
+ *
+ * https://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.framework.autoproxy.target;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.aop.TargetSource;
+import org.springframework.aop.framework.AopInfrastructureBean;
+import org.springframework.aop.framework.autoproxy.TargetSourceCreator;
+import org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.support.GenericBeanDefinition;
+import org.springframework.lang.Nullable;
+
+/**
+ * Convenient superclass for
+ * {@link org.springframework.aop.framework.autoproxy.TargetSourceCreator}
+ * implementations that require creating multiple instances of a prototype bean.
+ *
+ *
Uses an internal BeanFactory to manage the target instances,
+ * copying the original bean definition to this internal factory.
+ * This is necessary because the original BeanFactory will just
+ * contain the proxy instance created through auto-proxying.
+ *
+ *
Requires running in an
+ * {@link org.springframework.beans.factory.support.AbstractBeanFactory}.
+ *
+ * @author Rod Johnson
+ * @author Juergen Hoeller
+ * @see org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource
+ * @see org.springframework.beans.factory.support.AbstractBeanFactory
+ */
+public abstract class AbstractBeanFactoryBasedTargetSourceCreator
+ implements TargetSourceCreator, BeanFactoryAware, DisposableBean {
+
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private ConfigurableBeanFactory beanFactory;
+
+ /** Internally used DefaultListableBeanFactory instances, keyed by bean name. */
+ private final Map internalBeanFactories =
+ new HashMap<>();
+
+
+ @Override
+ public final void setBeanFactory(BeanFactory beanFactory) {
+ if (!(beanFactory instanceof ConfigurableBeanFactory)) {
+ throw new IllegalStateException("Cannot do auto-TargetSource creation with a BeanFactory " +
+ "that doesn't implement ConfigurableBeanFactory: " + beanFactory.getClass());
+ }
+ this.beanFactory = (ConfigurableBeanFactory) beanFactory;
+ }
+
+ /**
+ * Return the BeanFactory that this TargetSourceCreators runs in.
+ */
+ protected final BeanFactory getBeanFactory() {
+ return this.beanFactory;
+ }
+
+
+ //---------------------------------------------------------------------
+ // Implementation of the TargetSourceCreator interface
+ //---------------------------------------------------------------------
+
+ @Override
+ @Nullable
+ public final TargetSource getTargetSource(Class> beanClass, String beanName) {
+ AbstractBeanFactoryBasedTargetSource targetSource =
+ createBeanFactoryBasedTargetSource(beanClass, beanName);
+ if (targetSource == null) {
+ return null;
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Configuring AbstractBeanFactoryBasedTargetSource: " + targetSource);
+ }
+
+ DefaultListableBeanFactory internalBeanFactory = getInternalBeanFactoryForBean(beanName);
+
+ // We need to override just this bean definition, as it may reference other beans
+ // and we're happy to take the parent's definition for those.
+ // Always use prototype scope if demanded.
+ BeanDefinition bd = this.beanFactory.getMergedBeanDefinition(beanName);
+ GenericBeanDefinition bdCopy = new GenericBeanDefinition(bd);
+ if (isPrototypeBased()) {
+ bdCopy.setScope(BeanDefinition.SCOPE_PROTOTYPE);
+ }
+ internalBeanFactory.registerBeanDefinition(beanName, bdCopy);
+
+ // Complete configuring the PrototypeTargetSource.
+ targetSource.setTargetBeanName(beanName);
+ targetSource.setBeanFactory(internalBeanFactory);
+
+ return targetSource;
+ }
+
+ /**
+ * Return the internal BeanFactory to be used for the specified bean.
+ * @param beanName the name of the target bean
+ * @return the internal BeanFactory to be used
+ */
+ protected DefaultListableBeanFactory getInternalBeanFactoryForBean(String beanName) {
+ synchronized (this.internalBeanFactories) {
+ DefaultListableBeanFactory internalBeanFactory = this.internalBeanFactories.get(beanName);
+ if (internalBeanFactory == null) {
+ internalBeanFactory = buildInternalBeanFactory(this.beanFactory);
+ this.internalBeanFactories.put(beanName, internalBeanFactory);
+ }
+ return internalBeanFactory;
+ }
+ }
+
+ /**
+ * Build an internal BeanFactory for resolving target beans.
+ * @param containingFactory the containing BeanFactory that originally defines the beans
+ * @return an independent internal BeanFactory to hold copies of some target beans
+ */
+ protected DefaultListableBeanFactory buildInternalBeanFactory(ConfigurableBeanFactory containingFactory) {
+ // Set parent so that references (up container hierarchies) are correctly resolved.
+ DefaultListableBeanFactory internalBeanFactory = new DefaultListableBeanFactory(containingFactory);
+
+ // Required so that all BeanPostProcessors, Scopes, etc become available.
+ internalBeanFactory.copyConfigurationFrom(containingFactory);
+
+ // Filter out BeanPostProcessors that are part of the AOP infrastructure,
+ // since those are only meant to apply to beans defined in the original factory.
+ internalBeanFactory.getBeanPostProcessors().removeIf(beanPostProcessor ->
+ beanPostProcessor instanceof AopInfrastructureBean);
+
+ return internalBeanFactory;
+ }
+
+ /**
+ * Destroys the internal BeanFactory on shutdown of the TargetSourceCreator.
+ * @see #getInternalBeanFactoryForBean
+ */
+ @Override
+ public void destroy() {
+ synchronized (this.internalBeanFactories) {
+ for (DefaultListableBeanFactory bf : this.internalBeanFactories.values()) {
+ bf.destroySingletons();
+ }
+ }
+ }
+
+
+ //---------------------------------------------------------------------
+ // Template methods to be implemented by subclasses
+ //---------------------------------------------------------------------
+
+ /**
+ * Return whether this TargetSourceCreator is prototype-based.
+ * The scope of the target bean definition will be set accordingly.
+ *
Default is "true".
+ * @see org.springframework.beans.factory.config.BeanDefinition#isSingleton()
+ */
+ protected boolean isPrototypeBased() {
+ return true;
+ }
+
+ /**
+ * Subclasses must implement this method to return a new AbstractPrototypeBasedTargetSource
+ * if they wish to create a custom TargetSource for this bean, or {@code null} if they are
+ * not interested it in, in which case no special target source will be created.
+ * Subclasses should not call {@code setTargetBeanName} or {@code setBeanFactory}
+ * on the AbstractPrototypeBasedTargetSource: This class' implementation of
+ * {@code getTargetSource()} will do that.
+ * @param beanClass the class of the bean to create a TargetSource for
+ * @param beanName the name of the bean
+ * @return the AbstractPrototypeBasedTargetSource, or {@code null} if we don't match this
+ */
+ @Nullable
+ protected abstract AbstractBeanFactoryBasedTargetSource createBeanFactoryBasedTargetSource(
+ Class> beanClass, String beanName);
+
+}
diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/target/LazyInitTargetSourceCreator.java b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/target/LazyInitTargetSourceCreator.java
new file mode 100644
index 0000000000000000000000000000000000000000..5761068e8aa22b38db822014650fb3b71cd3e958
--- /dev/null
+++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/target/LazyInitTargetSourceCreator.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2002-2014 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
+ *
+ * https://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.framework.autoproxy.target;
+
+import org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource;
+import org.springframework.aop.target.LazyInitTargetSource;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.lang.Nullable;
+
+/**
+ * TargetSourceCreator that enforces a LazyInitTargetSource for each bean
+ * that is defined as "lazy-init". This will lead to a proxy created for
+ * each of those beans, allowing to fetch a reference to such a bean
+ * without actually initializing the target bean instance.
+ *
+ *
To be registered as custom TargetSourceCreator for an auto-proxy creator,
+ * in combination with custom interceptors for specific beans or for the
+ * creation of lazy-init proxies only. For example, as autodetected
+ * infrastructure bean in an XML application context definition:
+ *
+ *
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see org.springframework.beans.factory.config.BeanDefinition#isLazyInit
+ * @see org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#setCustomTargetSourceCreators
+ * @see org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator
+ */
+public class LazyInitTargetSourceCreator extends AbstractBeanFactoryBasedTargetSourceCreator {
+
+ @Override
+ protected boolean isPrototypeBased() {
+ return false;
+ }
+
+ @Override
+ @Nullable
+ protected AbstractBeanFactoryBasedTargetSource createBeanFactoryBasedTargetSource(
+ Class> beanClass, String beanName) {
+
+ if (getBeanFactory() instanceof ConfigurableListableBeanFactory) {
+ BeanDefinition definition =
+ ((ConfigurableListableBeanFactory) getBeanFactory()).getBeanDefinition(beanName);
+ if (definition.isLazyInit()) {
+ return new LazyInitTargetSource();
+ }
+ }
+ return null;
+ }
+
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..a6a741e0f879defeafaf7fd127211a232e323a06
--- /dev/null
+++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/target/QuickTargetSourceCreator.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2002-2018 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
+ *
+ * https://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.framework.autoproxy.target;
+
+import org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource;
+import org.springframework.aop.target.CommonsPool2TargetSource;
+import org.springframework.aop.target.PrototypeTargetSource;
+import org.springframework.aop.target.ThreadLocalTargetSource;
+import org.springframework.lang.Nullable;
+
+/**
+ * Convenient TargetSourceCreator using bean name prefixes to create one of three
+ * well-known TargetSource types:
+ *
: CommonsPool2TargetSource
+ *
% ThreadLocalTargetSource
+ *
! PrototypeTargetSource
+ *
+ * @author Rod Johnson
+ * @author Stephane Nicoll
+ * @see org.springframework.aop.target.CommonsPool2TargetSource
+ * @see org.springframework.aop.target.ThreadLocalTargetSource
+ * @see org.springframework.aop.target.PrototypeTargetSource
+ */
+public class QuickTargetSourceCreator extends AbstractBeanFactoryBasedTargetSourceCreator {
+
+ /**
+ * The CommonsPool2TargetSource prefix.
+ */
+ public static final String PREFIX_COMMONS_POOL = ":";
+
+ /**
+ * The ThreadLocalTargetSource prefix.
+ */
+ public static final String PREFIX_THREAD_LOCAL = "%";
+
+ /**
+ * The PrototypeTargetSource prefix.
+ */
+ public static final String PREFIX_PROTOTYPE = "!";
+
+ @Override
+ @Nullable
+ protected final AbstractBeanFactoryBasedTargetSource createBeanFactoryBasedTargetSource(
+ Class> beanClass, String beanName) {
+
+ if (beanName.startsWith(PREFIX_COMMONS_POOL)) {
+ CommonsPool2TargetSource cpts = new CommonsPool2TargetSource();
+ cpts.setMaxSize(25);
+ return cpts;
+ }
+ else if (beanName.startsWith(PREFIX_THREAD_LOCAL)) {
+ return new ThreadLocalTargetSource();
+ }
+ else if (beanName.startsWith(PREFIX_PROTOTYPE)) {
+ return new PrototypeTargetSource();
+ }
+ else {
+ // No match. Don't create a custom target source.
+ return null;
+ }
+ }
+
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..cf32c396d847949c539478828b2ee7d9d4149e34
--- /dev/null
+++ b/spring-aop/src/main/java/org/springframework/aop/target/AbstractBeanFactoryBasedTargetSource.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2002-2018 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
+ *
+ * https://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 java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.aop.TargetSource;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.util.ObjectUtils;
+
+/**
+ * Base class for {@link org.springframework.aop.TargetSource} implementations
+ * that are based on a Spring {@link org.springframework.beans.factory.BeanFactory},
+ * delegating to Spring-managed bean instances.
+ *
+ *
Subclasses can create prototype instances or lazily access a
+ * singleton target, for example. See {@link LazyInitTargetSource} and
+ * {@link AbstractPrototypeBasedTargetSource}'s subclasses for concrete strategies.
+ *
+ *
BeanFactory-based TargetSources are serializable. This involves
+ * disconnecting the current target and turning into a {@link SingletonTargetSource}.
+ *
+ * @author Juergen Hoeller
+ * @author Rod Johnson
+ * @since 1.1.4
+ * @see org.springframework.beans.factory.BeanFactory#getBean
+ * @see LazyInitTargetSource
+ * @see PrototypeTargetSource
+ * @see ThreadLocalTargetSource
+ * @see CommonsPool2TargetSource
+ */
+public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSource, BeanFactoryAware, Serializable {
+
+ /** use serialVersionUID from Spring 1.2.7 for interoperability. */
+ private static final long serialVersionUID = -4721607536018568393L;
+
+
+ /** Logger available to subclasses. */
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ /** Name of the target bean we will create on each invocation. */
+ private String targetBeanName;
+
+ /** Class of the target. */
+ private volatile Class> targetClass;
+
+ /**
+ * BeanFactory that owns this TargetSource. We need to hold onto this
+ * reference so that we can create new prototype instances as necessary.
+ */
+ private BeanFactory beanFactory;
+
+
+ /**
+ * Set the name of the target bean in the factory.
+ *
The target bean should not be a singleton, else the same instance will
+ * always be obtained from the factory, resulting in the same behavior as
+ * provided by {@link SingletonTargetSource}.
+ * @param targetBeanName name of the target bean in the BeanFactory
+ * that owns this interceptor
+ * @see SingletonTargetSource
+ */
+ public void setTargetBeanName(String targetBeanName) {
+ this.targetBeanName = targetBeanName;
+ }
+
+ /**
+ * Return the name of the target bean in the factory.
+ */
+ public String getTargetBeanName() {
+ return this.targetBeanName;
+ }
+
+ /**
+ * Specify the target class explicitly, to avoid any kind of access to the
+ * target bean (for example, to avoid initialization of a FactoryBean instance).
+ *
Default is to detect the type automatically, through a {@code getType}
+ * call on the BeanFactory (or even a full {@code getBean} call as fallback).
+ */
+ public void setTargetClass(Class> targetClass) {
+ this.targetClass = targetClass;
+ }
+
+ /**
+ * Set the owning BeanFactory. We need to save a reference so that we can
+ * use the {@code getBean} method on every invocation.
+ */
+ @Override
+ public void setBeanFactory(BeanFactory beanFactory) {
+ if (this.targetBeanName == null) {
+ throw new IllegalStateException("Property 'targetBeanName' is required");
+ }
+ this.beanFactory = beanFactory;
+ }
+
+ /**
+ * Return the owning BeanFactory.
+ */
+ public BeanFactory getBeanFactory() {
+ return this.beanFactory;
+ }
+
+
+ @Override
+ public Class> getTargetClass() {
+ Class> targetClass = this.targetClass;
+ if (targetClass != null) {
+ return targetClass;
+ }
+ synchronized (this) {
+ // Full check within synchronization, entering the BeanFactory interaction algorithm only once...
+ targetClass = this.targetClass;
+ if (targetClass == null && this.beanFactory != null) {
+ // Determine type of the target bean.
+ targetClass = this.beanFactory.getType(this.targetBeanName);
+ if (targetClass == null) {
+ if (logger.isTraceEnabled()) {
+ logger.trace("Getting bean with name '" + this.targetBeanName + "' for type determination");
+ }
+ Object beanInstance = this.beanFactory.getBean(this.targetBeanName);
+ targetClass = beanInstance.getClass();
+ }
+ this.targetClass = targetClass;
+ }
+ return targetClass;
+ }
+ }
+
+ @Override
+ public boolean isStatic() {
+ return false;
+ }
+
+ @Override
+ public void releaseTarget(Object target) throws Exception {
+ // Nothing to do here.
+ }
+
+
+ /**
+ * Copy configuration from the other AbstractBeanFactoryBasedTargetSource object.
+ * Subclasses should override this if they wish to expose it.
+ * @param other object to copy configuration from
+ */
+ protected void copyFrom(AbstractBeanFactoryBasedTargetSource other) {
+ this.targetBeanName = other.targetBeanName;
+ this.targetClass = other.targetClass;
+ this.beanFactory = other.beanFactory;
+ }
+
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other == null || getClass() != other.getClass()) {
+ return false;
+ }
+ AbstractBeanFactoryBasedTargetSource otherTargetSource = (AbstractBeanFactoryBasedTargetSource) other;
+ return (ObjectUtils.nullSafeEquals(this.beanFactory, otherTargetSource.beanFactory) &&
+ ObjectUtils.nullSafeEquals(this.targetBeanName, otherTargetSource.targetBeanName));
+ }
+
+ @Override
+ public int hashCode() {
+ int hashCode = getClass().hashCode();
+ hashCode = 13 * hashCode + ObjectUtils.nullSafeHashCode(this.beanFactory);
+ hashCode = 13 * hashCode + ObjectUtils.nullSafeHashCode(this.targetBeanName);
+ return hashCode;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(getClass().getSimpleName());
+ sb.append(" for target bean '").append(this.targetBeanName).append("'");
+ if (this.targetClass != null) {
+ sb.append(" of type [").append(this.targetClass.getName()).append("]");
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/spring-aop/src/main/java/org/springframework/aop/target/AbstractLazyCreationTargetSource.java b/spring-aop/src/main/java/org/springframework/aop/target/AbstractLazyCreationTargetSource.java
new file mode 100644
index 0000000000000000000000000000000000000000..f742a106bab8ce3b5cf3c8fe45d881afad1826e8
--- /dev/null
+++ b/spring-aop/src/main/java/org/springframework/aop/target/AbstractLazyCreationTargetSource.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2002-2018 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
+ *
+ * https://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.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.aop.TargetSource;
+import org.springframework.lang.Nullable;
+
+/**
+ * {@link org.springframework.aop.TargetSource} implementation that will
+ * lazily create a user-managed object.
+ *
+ *
Creation of the lazy target object is controlled by the user by implementing
+ * the {@link #createObject()} method. This {@code TargetSource} will invoke
+ * this method the first time the proxy is accessed.
+ *
+ *
Useful when you need to pass a reference to some dependency to an object
+ * but you don't actually want the dependency to be created until it is first used.
+ * A typical scenario for this is a connection to a remote resource.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2.4
+ * @see #isInitialized()
+ * @see #createObject()
+ */
+public abstract class AbstractLazyCreationTargetSource implements TargetSource {
+
+ /** Logger available to subclasses. */
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ /** The lazily initialized target object. */
+ private Object lazyTarget;
+
+
+ /**
+ * Return whether the lazy target object of this TargetSource
+ * has already been fetched.
+ */
+ public synchronized boolean isInitialized() {
+ return (this.lazyTarget != null);
+ }
+
+ /**
+ * This default implementation returns {@code null} if the
+ * target is {@code null} (it is hasn't yet been initialized),
+ * or the target class if the target has already been initialized.
+ *
Subclasses may wish to override this method in order to provide
+ * a meaningful value when the target is still {@code null}.
+ * @see #isInitialized()
+ */
+ @Override
+ @Nullable
+ public synchronized Class> getTargetClass() {
+ return (this.lazyTarget != null ? this.lazyTarget.getClass() : null);
+ }
+
+ @Override
+ public boolean isStatic() {
+ return false;
+ }
+
+ /**
+ * Returns the lazy-initialized target object,
+ * creating it on-the-fly if it doesn't exist already.
+ * @see #createObject()
+ */
+ @Override
+ public synchronized Object getTarget() throws Exception {
+ if (this.lazyTarget == null) {
+ logger.debug("Initializing lazy target object");
+ this.lazyTarget = createObject();
+ }
+ return this.lazyTarget;
+ }
+
+ @Override
+ public void releaseTarget(Object target) throws Exception {
+ // nothing to do
+ }
+
+
+ /**
+ * Subclasses should implement this method to return the lazy initialized object.
+ * Called the first time the proxy is invoked.
+ * @return the created object
+ * @throws Exception if creation failed
+ */
+ protected abstract Object createObject() throws Exception;
+
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..59017bfabeba9e61311d1ef6ccb31a5d0ba4f198
--- /dev/null
+++ b/spring-aop/src/main/java/org/springframework/aop/target/AbstractPoolingTargetSource.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2002-2018 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
+ *
+ * https://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.springframework.aop.support.DefaultIntroductionAdvisor;
+import org.springframework.aop.support.DelegatingIntroductionInterceptor;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanInitializationException;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.lang.Nullable;
+
+/**
+ * Abstract base class for pooling {@link org.springframework.aop.TargetSource}
+ * 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 CommonsPool2TargetSource} for a concrete example.
+ *
+ *
Subclasses must implement the {@link #getTarget} and
+ * {@link #releaseTarget} methods based on their chosen object pool.
+ * The {@link #newPrototypeInstance()} method inherited from
+ * {@link AbstractPrototypeBasedTargetSource} can be used to create objects
+ * in order to put them into the pool.
+ *
+ *
Subclasses must also implement some of the monitoring methods from the
+ * {@link PoolingConfig} interface. The {@link #getPoolingConfigMixin()} method
+ * makes these stats available on proxied objects through an IntroductionAdvisor.
+ *
+ *
This class implements the {@link org.springframework.beans.factory.DisposableBean}
+ * interface in order to force subclasses to implement a {@link #destroy()}
+ * method, closing down their object pool.
+ *
+ * @author Rod Johnson
+ * @author Juergen Hoeller
+ * @see #getTarget
+ * @see #releaseTarget
+ * @see #destroy
+ */
+@SuppressWarnings("serial")
+public abstract class AbstractPoolingTargetSource extends AbstractPrototypeBasedTargetSource
+ implements PoolingConfig, DisposableBean {
+
+ /** The maximum size of the pool. */
+ private int maxSize = -1;
+
+
+ /**
+ * Set the maximum size of the pool.
+ * Default is -1, indicating no size limit.
+ */
+ public void setMaxSize(int maxSize) {
+ this.maxSize = maxSize;
+ }
+
+ /**
+ * Return the maximum size of the pool.
+ */
+ @Override
+ public int getMaxSize() {
+ return this.maxSize;
+ }
+
+
+ @Override
+ public final void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ super.setBeanFactory(beanFactory);
+ try {
+ createPool();
+ }
+ catch (Throwable ex) {
+ throw new BeanInitializationException("Could not create instance pool for TargetSource", ex);
+ }
+ }
+
+
+ /**
+ * Create the pool.
+ * @throws Exception to avoid placing constraints on pooling APIs
+ */
+ protected abstract void createPool() throws Exception;
+
+ /**
+ * Acquire an object from the pool.
+ * @return an object from the pool
+ * @throws Exception we may need to deal with checked exceptions from pool
+ * APIs, so we're forgiving with our exception signature
+ */
+ @Override
+ @Nullable
+ public abstract Object getTarget() throws Exception;
+
+ /**
+ * Return the given object to the pool.
+ * @param target object that must have been acquired from the pool
+ * via a call to {@code getTarget()}
+ * @throws Exception to allow pooling APIs to throw exception
+ * @see #getTarget
+ */
+ @Override
+ public abstract void releaseTarget(Object target) throws Exception;
+
+
+ /**
+ * Return an IntroductionAdvisor that providing a mixin
+ * exposing statistics about the pool maintained by this object.
+ */
+ public DefaultIntroductionAdvisor getPoolingConfigMixin() {
+ DelegatingIntroductionInterceptor dii = new DelegatingIntroductionInterceptor(this);
+ return new DefaultIntroductionAdvisor(dii, PoolingConfig.class);
+ }
+
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..b3c564743b8df13147d8eca5a621c69dd43f0160
--- /dev/null
+++ b/spring-aop/src/main/java/org/springframework/aop/target/AbstractPrototypeBasedTargetSource.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2002-2018 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
+ *
+ * https://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 java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamException;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanDefinitionStoreException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+
+/**
+ * Base class for dynamic {@link org.springframework.aop.TargetSource} implementations
+ * that create new prototype bean instances to support a pooling or
+ * new-instance-per-invocation strategy.
+ *
+ *
Such TargetSources must run in a {@link BeanFactory}, as it needs to
+ * call the {@code getBean} method to create a new prototype instance.
+ * Therefore, this base class extends {@link AbstractBeanFactoryBasedTargetSource}.
+ *
+ * @author Rod Johnson
+ * @author Juergen Hoeller
+ * @see org.springframework.beans.factory.BeanFactory#getBean
+ * @see PrototypeTargetSource
+ * @see ThreadLocalTargetSource
+ * @see CommonsPool2TargetSource
+ */
+@SuppressWarnings("serial")
+public abstract class AbstractPrototypeBasedTargetSource extends AbstractBeanFactoryBasedTargetSource {
+
+ @Override
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ super.setBeanFactory(beanFactory);
+
+ // Check whether the target bean is defined as prototype.
+ if (!beanFactory.isPrototype(getTargetBeanName())) {
+ throw new BeanDefinitionStoreException(
+ "Cannot use prototype-based TargetSource against non-prototype bean with name '" +
+ getTargetBeanName() + "': instances would not be independent");
+ }
+ }
+
+ /**
+ * Subclasses should call this method to create a new prototype instance.
+ * @throws BeansException if bean creation failed
+ */
+ protected Object newPrototypeInstance() throws BeansException {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Creating new instance of bean '" + getTargetBeanName() + "'");
+ }
+ return getBeanFactory().getBean(getTargetBeanName());
+ }
+
+ /**
+ * Subclasses should call this method to destroy an obsolete prototype instance.
+ * @param target the bean instance to destroy
+ */
+ protected void destroyPrototypeInstance(Object target) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Destroying instance of bean '" + getTargetBeanName() + "'");
+ }
+ if (getBeanFactory() instanceof ConfigurableBeanFactory) {
+ ((ConfigurableBeanFactory) getBeanFactory()).destroyBean(getTargetBeanName(), target);
+ }
+ else if (target instanceof DisposableBean) {
+ try {
+ ((DisposableBean) target).destroy();
+ }
+ catch (Throwable ex) {
+ logger.warn("Destroy method on bean with name '" + getTargetBeanName() + "' threw an exception", ex);
+ }
+ }
+ }
+
+
+ //---------------------------------------------------------------------
+ // Serialization support
+ //---------------------------------------------------------------------
+
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ throw new NotSerializableException("A prototype-based TargetSource itself is not deserializable - " +
+ "just a disconnected SingletonTargetSource or EmptyTargetSource is");
+ }
+
+ /**
+ * Replaces this object with a SingletonTargetSource on serialization.
+ * Protected as otherwise it won't be invoked for subclasses.
+ * (The {@code writeReplace()} method must be visible to the class
+ * being serialized.)
+ *
With this implementation of this method, there is no need to mark
+ * non-serializable fields in this class or subclasses as transient.
+ */
+ protected Object writeReplace() throws ObjectStreamException {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Disconnecting TargetSource [" + this + "]");
+ }
+ try {
+ // Create disconnected SingletonTargetSource/EmptyTargetSource.
+ Object target = getTarget();
+ return (target != null ? new SingletonTargetSource(target) :
+ EmptyTargetSource.forClass(getTargetClass()));
+ }
+ catch (Exception ex) {
+ String msg = "Cannot get target for disconnecting TargetSource [" + this + "]";
+ logger.error(msg, ex);
+ throw new NotSerializableException(msg + ": " + ex);
+ }
+ }
+
+}
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 0000000000000000000000000000000000000000..4733d02696fd30a0f9cad74d9eb4e59b5c9391ee
--- /dev/null
+++ b/spring-aop/src/main/java/org/springframework/aop/target/CommonsPool2TargetSource.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2002-2018 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
+ *
+ * https://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;
+
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+
+/**
+ * {@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.
+ *
+ *
Compatible with Apache Commons Pool 2.4, as of Spring 4.2.
+ *
+ * @author Rod Johnson
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @author Stephane Nicoll
+ * @author Kazuki Shimizu
+ * @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