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.Map; 021 022import org.apache.commons.logging.Log; 023import org.apache.commons.logging.LogFactory; 024 025import org.springframework.aop.TargetSource; 026import org.springframework.aop.framework.AopInfrastructureBean; 027import org.springframework.aop.framework.autoproxy.TargetSourceCreator; 028import org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource; 029import org.springframework.beans.factory.BeanFactory; 030import org.springframework.beans.factory.BeanFactoryAware; 031import org.springframework.beans.factory.DisposableBean; 032import org.springframework.beans.factory.config.BeanDefinition; 033import org.springframework.beans.factory.config.ConfigurableBeanFactory; 034import org.springframework.beans.factory.support.DefaultListableBeanFactory; 035import org.springframework.beans.factory.support.GenericBeanDefinition; 036import org.springframework.lang.Nullable; 037 038/** 039 * Convenient superclass for 040 * {@link org.springframework.aop.framework.autoproxy.TargetSourceCreator} 041 * implementations that require creating multiple instances of a prototype bean. 042 * 043 * <p>Uses an internal BeanFactory to manage the target instances, 044 * copying the original bean definition to this internal factory. 045 * This is necessary because the original BeanFactory will just 046 * contain the proxy instance created through auto-proxying. 047 * 048 * <p>Requires running in an 049 * {@link org.springframework.beans.factory.support.AbstractBeanFactory}. 050 * 051 * @author Rod Johnson 052 * @author Juergen Hoeller 053 * @see org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource 054 * @see org.springframework.beans.factory.support.AbstractBeanFactory 055 */ 056public abstract class AbstractBeanFactoryBasedTargetSourceCreator 057 implements TargetSourceCreator, BeanFactoryAware, DisposableBean { 058 059 protected final Log logger = LogFactory.getLog(getClass()); 060 061 private ConfigurableBeanFactory beanFactory; 062 063 /** Internally used DefaultListableBeanFactory instances, keyed by bean name. */ 064 private final Map<String, DefaultListableBeanFactory> internalBeanFactories = 065 new HashMap<>(); 066 067 068 @Override 069 public final void setBeanFactory(BeanFactory beanFactory) { 070 if (!(beanFactory instanceof ConfigurableBeanFactory)) { 071 throw new IllegalStateException("Cannot do auto-TargetSource creation with a BeanFactory " + 072 "that doesn't implement ConfigurableBeanFactory: " + beanFactory.getClass()); 073 } 074 this.beanFactory = (ConfigurableBeanFactory) beanFactory; 075 } 076 077 /** 078 * Return the BeanFactory that this TargetSourceCreators runs in. 079 */ 080 protected final BeanFactory getBeanFactory() { 081 return this.beanFactory; 082 } 083 084 085 //--------------------------------------------------------------------- 086 // Implementation of the TargetSourceCreator interface 087 //--------------------------------------------------------------------- 088 089 @Override 090 @Nullable 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 internalBeanFactory.getBeanPostProcessors().removeIf(beanPostProcessor -> 152 beanPostProcessor instanceof AopInfrastructureBean); 153 154 return internalBeanFactory; 155 } 156 157 /** 158 * Destroys the internal BeanFactory on shutdown of the TargetSourceCreator. 159 * @see #getInternalBeanFactoryForBean 160 */ 161 @Override 162 public void destroy() { 163 synchronized (this.internalBeanFactories) { 164 for (DefaultListableBeanFactory bf : this.internalBeanFactories.values()) { 165 bf.destroySingletons(); 166 } 167 } 168 } 169 170 171 //--------------------------------------------------------------------- 172 // Template methods to be implemented by subclasses 173 //--------------------------------------------------------------------- 174 175 /** 176 * Return whether this TargetSourceCreator is prototype-based. 177 * The scope of the target bean definition will be set accordingly. 178 * <p>Default is "true". 179 * @see org.springframework.beans.factory.config.BeanDefinition#isSingleton() 180 */ 181 protected boolean isPrototypeBased() { 182 return true; 183 } 184 185 /** 186 * Subclasses must implement this method to return a new AbstractPrototypeBasedTargetSource 187 * if they wish to create a custom TargetSource for this bean, or {@code null} if they are 188 * not interested it in, in which case no special target source will be created. 189 * Subclasses should not call {@code setTargetBeanName} or {@code setBeanFactory} 190 * on the AbstractPrototypeBasedTargetSource: This class' implementation of 191 * {@code getTargetSource()} will do that. 192 * @param beanClass the class of the bean to create a TargetSource for 193 * @param beanName the name of the bean 194 * @return the AbstractPrototypeBasedTargetSource, or {@code null} if we don't match this 195 */ 196 @Nullable 197 protected abstract AbstractBeanFactoryBasedTargetSource createBeanFactoryBasedTargetSource( 198 Class<?> beanClass, String beanName); 199 200}