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.framework.autoproxy.target; 018 019import java.util.HashMap; 020import java.util.Iterator; 021import java.util.Map; 022 023import org.apache.commons.logging.Log; 024import org.apache.commons.logging.LogFactory; 025 026import org.springframework.aop.TargetSource; 027import org.springframework.aop.framework.AopInfrastructureBean; 028import org.springframework.aop.framework.autoproxy.TargetSourceCreator; 029import org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource; 030import org.springframework.beans.factory.BeanFactory; 031import org.springframework.beans.factory.BeanFactoryAware; 032import org.springframework.beans.factory.DisposableBean; 033import org.springframework.beans.factory.config.BeanDefinition; 034import org.springframework.beans.factory.config.BeanPostProcessor; 035import org.springframework.beans.factory.config.ConfigurableBeanFactory; 036import org.springframework.beans.factory.support.DefaultListableBeanFactory; 037import org.springframework.beans.factory.support.GenericBeanDefinition; 038 039/** 040 * Convenient superclass for 041 * {@link org.springframework.aop.framework.autoproxy.TargetSourceCreator} 042 * implementations that require creating multiple instances of a prototype bean. 043 * 044 * <p>Uses an internal BeanFactory to manage the target instances, 045 * copying the original bean definition to this internal factory. 046 * This is necessary because the original BeanFactory will just 047 * contain the proxy instance created through auto-proxying. 048 * 049 * <p>Requires running in an 050 * {@link org.springframework.beans.factory.support.AbstractBeanFactory}. 051 * 052 * @author Rod Johnson 053 * @author Juergen Hoeller 054 * @see org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource 055 * @see org.springframework.beans.factory.support.AbstractBeanFactory 056 */ 057public abstract class AbstractBeanFactoryBasedTargetSourceCreator 058 implements TargetSourceCreator, BeanFactoryAware, DisposableBean { 059 060 protected final Log logger = LogFactory.getLog(getClass()); 061 062 private ConfigurableBeanFactory beanFactory; 063 064 /** Internally used DefaultListableBeanFactory instances, keyed by bean name */ 065 private final Map<String, DefaultListableBeanFactory> internalBeanFactories = 066 new HashMap<String, DefaultListableBeanFactory>(); 067 068 069 @Override 070 public final void setBeanFactory(BeanFactory beanFactory) { 071 if (!(beanFactory instanceof ConfigurableBeanFactory)) { 072 throw new IllegalStateException("Cannot do auto-TargetSource creation with a BeanFactory " + 073 "that doesn't implement ConfigurableBeanFactory: " + beanFactory.getClass()); 074 } 075 this.beanFactory = (ConfigurableBeanFactory) beanFactory; 076 } 077 078 /** 079 * Return the BeanFactory that this TargetSourceCreators runs in. 080 */ 081 protected final BeanFactory getBeanFactory() { 082 return this.beanFactory; 083 } 084 085 086 //--------------------------------------------------------------------- 087 // Implementation of the TargetSourceCreator interface 088 //--------------------------------------------------------------------- 089 090 @Override 091 public final TargetSource getTargetSource(Class<?> beanClass, String beanName) { 092 AbstractBeanFactoryBasedTargetSource targetSource = 093 createBeanFactoryBasedTargetSource(beanClass, beanName); 094 if (targetSource == null) { 095 return null; 096 } 097 098 if (logger.isDebugEnabled()) { 099 logger.debug("Configuring AbstractBeanFactoryBasedTargetSource: " + targetSource); 100 } 101 102 DefaultListableBeanFactory internalBeanFactory = getInternalBeanFactoryForBean(beanName); 103 104 // We need to override just this bean definition, as it may reference other beans 105 // and we're happy to take the parent's definition for those. 106 // Always use prototype scope if demanded. 107 BeanDefinition bd = this.beanFactory.getMergedBeanDefinition(beanName); 108 GenericBeanDefinition bdCopy = new GenericBeanDefinition(bd); 109 if (isPrototypeBased()) { 110 bdCopy.setScope(BeanDefinition.SCOPE_PROTOTYPE); 111 } 112 internalBeanFactory.registerBeanDefinition(beanName, bdCopy); 113 114 // Complete configuring the PrototypeTargetSource. 115 targetSource.setTargetBeanName(beanName); 116 targetSource.setBeanFactory(internalBeanFactory); 117 118 return targetSource; 119 } 120 121 /** 122 * Return the internal BeanFactory to be used for the specified bean. 123 * @param beanName the name of the target bean 124 * @return the internal BeanFactory to be used 125 */ 126 protected DefaultListableBeanFactory getInternalBeanFactoryForBean(String beanName) { 127 synchronized (this.internalBeanFactories) { 128 DefaultListableBeanFactory internalBeanFactory = this.internalBeanFactories.get(beanName); 129 if (internalBeanFactory == null) { 130 internalBeanFactory = buildInternalBeanFactory(this.beanFactory); 131 this.internalBeanFactories.put(beanName, internalBeanFactory); 132 } 133 return internalBeanFactory; 134 } 135 } 136 137 /** 138 * Build an internal BeanFactory for resolving target beans. 139 * @param containingFactory the containing BeanFactory that originally defines the beans 140 * @return an independent internal BeanFactory to hold copies of some target beans 141 */ 142 protected DefaultListableBeanFactory buildInternalBeanFactory(ConfigurableBeanFactory containingFactory) { 143 // Set parent so that references (up container hierarchies) are correctly resolved. 144 DefaultListableBeanFactory internalBeanFactory = new DefaultListableBeanFactory(containingFactory); 145 146 // Required so that all BeanPostProcessors, Scopes, etc become available. 147 internalBeanFactory.copyConfigurationFrom(containingFactory); 148 149 // Filter out BeanPostProcessors that are part of the AOP infrastructure, 150 // since those are only meant to apply to beans defined in the original factory. 151 for (Iterator<BeanPostProcessor> it = internalBeanFactory.getBeanPostProcessors().iterator(); it.hasNext();) { 152 if (it.next() instanceof AopInfrastructureBean) { 153 it.remove(); // effectively deprecated: use List.removeIf on Java 8+ 154 } 155 } 156 157 return internalBeanFactory; 158 } 159 160 /** 161 * Destroys the internal BeanFactory on shutdown of the TargetSourceCreator. 162 * @see #getInternalBeanFactoryForBean 163 */ 164 @Override 165 public void destroy() { 166 synchronized (this.internalBeanFactories) { 167 for (DefaultListableBeanFactory bf : this.internalBeanFactories.values()) { 168 bf.destroySingletons(); 169 } 170 } 171 } 172 173 174 //--------------------------------------------------------------------- 175 // Template methods to be implemented by subclasses 176 //--------------------------------------------------------------------- 177 178 /** 179 * Return whether this TargetSourceCreator is prototype-based. 180 * The scope of the target bean definition will be set accordingly. 181 * <p>Default is "true". 182 * @see org.springframework.beans.factory.config.BeanDefinition#isSingleton() 183 */ 184 protected boolean isPrototypeBased() { 185 return true; 186 } 187 188 /** 189 * Subclasses must implement this method to return a new AbstractPrototypeBasedTargetSource 190 * if they wish to create a custom TargetSource for this bean, or {@code null} if they are 191 * not interested it in, in which case no special target source will be created. 192 * Subclasses should not call {@code setTargetBeanName} or {@code setBeanFactory} 193 * on the AbstractPrototypeBasedTargetSource: This class' implementation of 194 * {@code getTargetSource()} will do that. 195 * @param beanClass the class of the bean to create a TargetSource for 196 * @param beanName the name of the bean 197 * @return the AbstractPrototypeBasedTargetSource, or {@code null} if we don't match this 198 */ 199 protected abstract AbstractBeanFactoryBasedTargetSource createBeanFactoryBasedTargetSource( 200 Class<?> beanClass, String beanName); 201 202}