001/* 002 * Copyright 2002-2019 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; 018 019import java.beans.PropertyDescriptor; 020import java.lang.reflect.Constructor; 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.Collections; 024import java.util.List; 025import java.util.Map; 026import java.util.Set; 027import java.util.concurrent.ConcurrentHashMap; 028 029import org.aopalliance.aop.Advice; 030import org.apache.commons.logging.Log; 031import org.apache.commons.logging.LogFactory; 032 033import org.springframework.aop.Advisor; 034import org.springframework.aop.Pointcut; 035import org.springframework.aop.TargetSource; 036import org.springframework.aop.framework.AopInfrastructureBean; 037import org.springframework.aop.framework.ProxyFactory; 038import org.springframework.aop.framework.ProxyProcessorSupport; 039import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry; 040import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry; 041import org.springframework.aop.target.SingletonTargetSource; 042import org.springframework.beans.BeansException; 043import org.springframework.beans.PropertyValues; 044import org.springframework.beans.factory.BeanFactory; 045import org.springframework.beans.factory.BeanFactoryAware; 046import org.springframework.beans.factory.FactoryBean; 047import org.springframework.beans.factory.config.ConfigurableBeanFactory; 048import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 049import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor; 050import org.springframework.util.StringUtils; 051 052/** 053 * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation 054 * that wraps each eligible bean with an AOP proxy, delegating to specified interceptors 055 * before invoking the bean itself. 056 * 057 * <p>This class distinguishes between "common" interceptors: shared for all proxies it 058 * creates, and "specific" interceptors: unique per bean instance. There need not be any 059 * common interceptors. If there are, they are set using the interceptorNames property. 060 * As with {@link org.springframework.aop.framework.ProxyFactoryBean}, interceptors names 061 * in the current factory are used rather than bean references to allow correct handling 062 * of prototype advisors and interceptors: for example, to support stateful mixins. 063 * Any advice type is supported for {@link #setInterceptorNames "interceptorNames"} entries. 064 * 065 * <p>Such auto-proxying is particularly useful if there's a large number of beans that 066 * need to be wrapped with similar proxies, i.e. delegating to the same interceptors. 067 * Instead of x repetitive proxy definitions for x target beans, you can register 068 * one single such post processor with the bean factory to achieve the same effect. 069 * 070 * <p>Subclasses can apply any strategy to decide if a bean is to be proxied, e.g. by type, 071 * by name, by definition details, etc. They can also return additional interceptors that 072 * should just be applied to the specific bean instance. A simple concrete implementation is 073 * {@link BeanNameAutoProxyCreator}, identifying the beans to be proxied via given names. 074 * 075 * <p>Any number of {@link TargetSourceCreator} implementations can be used to create 076 * a custom target source: for example, to pool prototype objects. Auto-proxying will 077 * occur even if there is no advice, as long as a TargetSourceCreator specifies a custom 078 * {@link org.springframework.aop.TargetSource}. If there are no TargetSourceCreators set, 079 * or if none matches, a {@link org.springframework.aop.target.SingletonTargetSource} 080 * will be used by default to wrap the target bean instance. 081 * 082 * @author Juergen Hoeller 083 * @author Rod Johnson 084 * @author Rob Harrop 085 * @since 13.10.2003 086 * @see #setInterceptorNames 087 * @see #getAdvicesAndAdvisorsForBean 088 * @see BeanNameAutoProxyCreator 089 * @see DefaultAdvisorAutoProxyCreator 090 */ 091@SuppressWarnings("serial") 092public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport 093 implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { 094 095 /** 096 * Convenience constant for subclasses: Return value for "do not proxy". 097 * @see #getAdvicesAndAdvisorsForBean 098 */ 099 protected static final Object[] DO_NOT_PROXY = null; 100 101 /** 102 * Convenience constant for subclasses: Return value for 103 * "proxy without additional interceptors, just the common ones". 104 * @see #getAdvicesAndAdvisorsForBean 105 */ 106 protected static final Object[] PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS = new Object[0]; 107 108 109 /** Logger available to subclasses */ 110 protected final Log logger = LogFactory.getLog(getClass()); 111 112 /** Default is global AdvisorAdapterRegistry */ 113 private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance(); 114 115 /** 116 * Indicates whether or not the proxy should be frozen. Overridden from super 117 * to prevent the configuration from becoming frozen too early. 118 */ 119 private boolean freezeProxy = false; 120 121 /** Default is no common interceptors */ 122 private String[] interceptorNames = new String[0]; 123 124 private boolean applyCommonInterceptorsFirst = true; 125 126 private TargetSourceCreator[] customTargetSourceCreators; 127 128 private BeanFactory beanFactory; 129 130 private final Set<String> targetSourcedBeans = 131 Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16)); 132 133 private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<Object, Object>(16); 134 135 private final Map<Object, Class<?>> proxyTypes = new ConcurrentHashMap<Object, Class<?>>(16); 136 137 private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<Object, Boolean>(256); 138 139 140 /** 141 * Set whether or not the proxy should be frozen, preventing advice 142 * from being added to it once it is created. 143 * <p>Overridden from the super class to prevent the proxy configuration 144 * from being frozen before the proxy is created. 145 */ 146 @Override 147 public void setFrozen(boolean frozen) { 148 this.freezeProxy = frozen; 149 } 150 151 @Override 152 public boolean isFrozen() { 153 return this.freezeProxy; 154 } 155 156 /** 157 * Specify the {@link AdvisorAdapterRegistry} to use. 158 * <p>Default is the global {@link AdvisorAdapterRegistry}. 159 * @see org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry 160 */ 161 public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) { 162 this.advisorAdapterRegistry = advisorAdapterRegistry; 163 } 164 165 /** 166 * Set custom {@code TargetSourceCreators} to be applied in this order. 167 * If the list is empty, or they all return null, a {@link SingletonTargetSource} 168 * will be created for each bean. 169 * <p>Note that TargetSourceCreators will kick in even for target beans 170 * where no advices or advisors have been found. If a {@code TargetSourceCreator} 171 * returns a {@link TargetSource} for a specific bean, that bean will be proxied 172 * in any case. 173 * <p>{@code TargetSourceCreators} can only be invoked if this post processor is used 174 * in a {@link BeanFactory} and its {@link BeanFactoryAware} callback is triggered. 175 * @param targetSourceCreators the list of {@code TargetSourceCreators}. 176 * Ordering is significant: The {@code TargetSource} returned from the first matching 177 * {@code TargetSourceCreator} (that is, the first that returns non-null) will be used. 178 */ 179 public void setCustomTargetSourceCreators(TargetSourceCreator... targetSourceCreators) { 180 this.customTargetSourceCreators = targetSourceCreators; 181 } 182 183 /** 184 * Set the common interceptors. These must be bean names in the current factory. 185 * They can be of any advice or advisor type Spring supports. 186 * <p>If this property isn't set, there will be zero common interceptors. 187 * This is perfectly valid, if "specific" interceptors such as matching 188 * Advisors are all we want. 189 */ 190 public void setInterceptorNames(String... interceptorNames) { 191 this.interceptorNames = interceptorNames; 192 } 193 194 /** 195 * Set whether the common interceptors should be applied before bean-specific ones. 196 * Default is "true"; else, bean-specific interceptors will get applied first. 197 */ 198 public void setApplyCommonInterceptorsFirst(boolean applyCommonInterceptorsFirst) { 199 this.applyCommonInterceptorsFirst = applyCommonInterceptorsFirst; 200 } 201 202 @Override 203 public void setBeanFactory(BeanFactory beanFactory) { 204 this.beanFactory = beanFactory; 205 } 206 207 /** 208 * Return the owning {@link BeanFactory}. 209 * May be {@code null}, as this post-processor doesn't need to belong to a bean factory. 210 */ 211 protected BeanFactory getBeanFactory() { 212 return this.beanFactory; 213 } 214 215 216 @Override 217 public Class<?> predictBeanType(Class<?> beanClass, String beanName) { 218 if (this.proxyTypes.isEmpty()) { 219 return null; 220 } 221 Object cacheKey = getCacheKey(beanClass, beanName); 222 return this.proxyTypes.get(cacheKey); 223 } 224 225 @Override 226 public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException { 227 return null; 228 } 229 230 @Override 231 public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException { 232 Object cacheKey = getCacheKey(bean.getClass(), beanName); 233 this.earlyProxyReferences.put(cacheKey, bean); 234 return wrapIfNecessary(bean, beanName, cacheKey); 235 } 236 237 @Override 238 public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { 239 Object cacheKey = getCacheKey(beanClass, beanName); 240 241 if (beanName == null || !this.targetSourcedBeans.contains(beanName)) { 242 if (this.advisedBeans.containsKey(cacheKey)) { 243 return null; 244 } 245 if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { 246 this.advisedBeans.put(cacheKey, Boolean.FALSE); 247 return null; 248 } 249 } 250 251 // Create proxy here if we have a custom TargetSource. 252 // Suppresses unnecessary default instantiation of the target bean: 253 // The TargetSource will handle target instances in a custom fashion. 254 if (beanName != null) { 255 TargetSource targetSource = getCustomTargetSource(beanClass, beanName); 256 if (targetSource != null) { 257 this.targetSourcedBeans.add(beanName); 258 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); 259 Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); 260 this.proxyTypes.put(cacheKey, proxy.getClass()); 261 return proxy; 262 } 263 } 264 265 return null; 266 } 267 268 @Override 269 public boolean postProcessAfterInstantiation(Object bean, String beanName) { 270 return true; 271 } 272 273 @Override 274 public PropertyValues postProcessPropertyValues( 275 PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) { 276 277 return pvs; 278 } 279 280 @Override 281 public Object postProcessBeforeInitialization(Object bean, String beanName) { 282 return bean; 283 } 284 285 /** 286 * Create a proxy with the configured interceptors if the bean is 287 * identified as one to proxy by the subclass. 288 * @see #getAdvicesAndAdvisorsForBean 289 */ 290 @Override 291 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 292 if (bean != null) { 293 Object cacheKey = getCacheKey(bean.getClass(), beanName); 294 if (this.earlyProxyReferences.remove(cacheKey) != bean) { 295 return wrapIfNecessary(bean, beanName, cacheKey); 296 } 297 } 298 return bean; 299 } 300 301 302 /** 303 * Build a cache key for the given bean class and bean name. 304 * <p>Note: As of 4.2.3, this implementation does not return a concatenated 305 * class/name String anymore but rather the most efficient cache key possible: 306 * a plain bean name, prepended with {@link BeanFactory#FACTORY_BEAN_PREFIX} 307 * in case of a {@code FactoryBean}; or if no bean name specified, then the 308 * given bean {@code Class} as-is. 309 * @param beanClass the bean class 310 * @param beanName the bean name 311 * @return the cache key for the given class and name 312 */ 313 protected Object getCacheKey(Class<?> beanClass, String beanName) { 314 if (StringUtils.hasLength(beanName)) { 315 return (FactoryBean.class.isAssignableFrom(beanClass) ? 316 BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName); 317 } 318 else { 319 return beanClass; 320 } 321 } 322 323 /** 324 * Wrap the given bean if necessary, i.e. if it is eligible for being proxied. 325 * @param bean the raw bean instance 326 * @param beanName the name of the bean 327 * @param cacheKey the cache key for metadata access 328 * @return a proxy wrapping the bean, or the raw bean instance as-is 329 */ 330 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { 331 if (beanName != null && this.targetSourcedBeans.contains(beanName)) { 332 return bean; 333 } 334 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { 335 return bean; 336 } 337 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { 338 this.advisedBeans.put(cacheKey, Boolean.FALSE); 339 return bean; 340 } 341 342 // Create proxy if we have advice. 343 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); 344 if (specificInterceptors != DO_NOT_PROXY) { 345 this.advisedBeans.put(cacheKey, Boolean.TRUE); 346 Object proxy = createProxy( 347 bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); 348 this.proxyTypes.put(cacheKey, proxy.getClass()); 349 return proxy; 350 } 351 352 this.advisedBeans.put(cacheKey, Boolean.FALSE); 353 return bean; 354 } 355 356 /** 357 * Return whether the given bean class represents an infrastructure class 358 * that should never be proxied. 359 * <p>The default implementation considers Advices, Advisors and 360 * AopInfrastructureBeans as infrastructure classes. 361 * @param beanClass the class of the bean 362 * @return whether the bean represents an infrastructure class 363 * @see org.aopalliance.aop.Advice 364 * @see org.springframework.aop.Advisor 365 * @see org.springframework.aop.framework.AopInfrastructureBean 366 * @see #shouldSkip 367 */ 368 protected boolean isInfrastructureClass(Class<?> beanClass) { 369 boolean retVal = Advice.class.isAssignableFrom(beanClass) || 370 Pointcut.class.isAssignableFrom(beanClass) || 371 Advisor.class.isAssignableFrom(beanClass) || 372 AopInfrastructureBean.class.isAssignableFrom(beanClass); 373 if (retVal && logger.isTraceEnabled()) { 374 logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]"); 375 } 376 return retVal; 377 } 378 379 /** 380 * Subclasses should override this method to return {@code true} if the 381 * given bean should not be considered for auto-proxying by this post-processor. 382 * <p>Sometimes we need to be able to avoid this happening if it will lead to 383 * a circular reference. This implementation returns {@code false}. 384 * @param beanClass the class of the bean 385 * @param beanName the name of the bean 386 * @return whether to skip the given bean 387 */ 388 protected boolean shouldSkip(Class<?> beanClass, String beanName) { 389 return false; 390 } 391 392 /** 393 * Create a target source for bean instances. Uses any TargetSourceCreators if set. 394 * Returns {@code null} if no custom TargetSource should be used. 395 * <p>This implementation uses the "customTargetSourceCreators" property. 396 * Subclasses can override this method to use a different mechanism. 397 * @param beanClass the class of the bean to create a TargetSource for 398 * @param beanName the name of the bean 399 * @return a TargetSource for this bean 400 * @see #setCustomTargetSourceCreators 401 */ 402 protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) { 403 // We can't create fancy target sources for directly registered singletons. 404 if (this.customTargetSourceCreators != null && 405 this.beanFactory != null && this.beanFactory.containsBean(beanName)) { 406 for (TargetSourceCreator tsc : this.customTargetSourceCreators) { 407 TargetSource ts = tsc.getTargetSource(beanClass, beanName); 408 if (ts != null) { 409 // Found a matching TargetSource. 410 if (logger.isDebugEnabled()) { 411 logger.debug("TargetSourceCreator [" + tsc + 412 "] found custom TargetSource for bean with name '" + beanName + "'"); 413 } 414 return ts; 415 } 416 } 417 } 418 419 // No custom TargetSource found. 420 return null; 421 } 422 423 /** 424 * Create an AOP proxy for the given bean. 425 * @param beanClass the class of the bean 426 * @param beanName the name of the bean 427 * @param specificInterceptors the set of interceptors that is 428 * specific to this bean (may be empty, but not null) 429 * @param targetSource the TargetSource for the proxy, 430 * already pre-configured to access the bean 431 * @return the AOP proxy for the bean 432 * @see #buildAdvisors 433 */ 434 protected Object createProxy( 435 Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) { 436 437 if (this.beanFactory instanceof ConfigurableListableBeanFactory) { 438 AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); 439 } 440 441 ProxyFactory proxyFactory = new ProxyFactory(); 442 proxyFactory.copyFrom(this); 443 444 if (!proxyFactory.isProxyTargetClass()) { 445 if (shouldProxyTargetClass(beanClass, beanName)) { 446 proxyFactory.setProxyTargetClass(true); 447 } 448 else { 449 evaluateProxyInterfaces(beanClass, proxyFactory); 450 } 451 } 452 453 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); 454 proxyFactory.addAdvisors(advisors); 455 proxyFactory.setTargetSource(targetSource); 456 customizeProxyFactory(proxyFactory); 457 458 proxyFactory.setFrozen(this.freezeProxy); 459 if (advisorsPreFiltered()) { 460 proxyFactory.setPreFiltered(true); 461 } 462 463 return proxyFactory.getProxy(getProxyClassLoader()); 464 } 465 466 /** 467 * Determine whether the given bean should be proxied with its target class rather than its interfaces. 468 * <p>Checks the {@link AutoProxyUtils#PRESERVE_TARGET_CLASS_ATTRIBUTE "preserveTargetClass" attribute} 469 * of the corresponding bean definition. 470 * @param beanClass the class of the bean 471 * @param beanName the name of the bean 472 * @return whether the given bean should be proxied with its target class 473 * @see AutoProxyUtils#shouldProxyTargetClass 474 */ 475 protected boolean shouldProxyTargetClass(Class<?> beanClass, String beanName) { 476 return (this.beanFactory instanceof ConfigurableListableBeanFactory && 477 AutoProxyUtils.shouldProxyTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName)); 478 } 479 480 /** 481 * Return whether the Advisors returned by the subclass are pre-filtered 482 * to match the bean's target class already, allowing the ClassFilter check 483 * to be skipped when building advisors chains for AOP invocations. 484 * <p>Default is {@code false}. Subclasses may override this if they 485 * will always return pre-filtered Advisors. 486 * @return whether the Advisors are pre-filtered 487 * @see #getAdvicesAndAdvisorsForBean 488 * @see org.springframework.aop.framework.Advised#setPreFiltered 489 */ 490 protected boolean advisorsPreFiltered() { 491 return false; 492 } 493 494 /** 495 * Determine the advisors for the given bean, including the specific interceptors 496 * as well as the common interceptor, all adapted to the Advisor interface. 497 * @param beanName the name of the bean 498 * @param specificInterceptors the set of interceptors that is 499 * specific to this bean (may be empty, but not null) 500 * @return the list of Advisors for the given bean 501 */ 502 protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) { 503 // Handle prototypes correctly... 504 Advisor[] commonInterceptors = resolveInterceptorNames(); 505 506 List<Object> allInterceptors = new ArrayList<Object>(); 507 if (specificInterceptors != null) { 508 allInterceptors.addAll(Arrays.asList(specificInterceptors)); 509 if (commonInterceptors.length > 0) { 510 if (this.applyCommonInterceptorsFirst) { 511 allInterceptors.addAll(0, Arrays.asList(commonInterceptors)); 512 } 513 else { 514 allInterceptors.addAll(Arrays.asList(commonInterceptors)); 515 } 516 } 517 } 518 if (logger.isDebugEnabled()) { 519 int nrOfCommonInterceptors = commonInterceptors.length; 520 int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0); 521 logger.debug("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors + 522 " common interceptors and " + nrOfSpecificInterceptors + " specific interceptors"); 523 } 524 525 Advisor[] advisors = new Advisor[allInterceptors.size()]; 526 for (int i = 0; i < allInterceptors.size(); i++) { 527 advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i)); 528 } 529 return advisors; 530 } 531 532 /** 533 * Resolves the specified interceptor names to Advisor objects. 534 * @see #setInterceptorNames 535 */ 536 private Advisor[] resolveInterceptorNames() { 537 ConfigurableBeanFactory cbf = (this.beanFactory instanceof ConfigurableBeanFactory ? 538 (ConfigurableBeanFactory) this.beanFactory : null); 539 List<Advisor> advisors = new ArrayList<Advisor>(); 540 for (String beanName : this.interceptorNames) { 541 if (cbf == null || !cbf.isCurrentlyInCreation(beanName)) { 542 Object next = this.beanFactory.getBean(beanName); 543 advisors.add(this.advisorAdapterRegistry.wrap(next)); 544 } 545 } 546 return advisors.toArray(new Advisor[advisors.size()]); 547 } 548 549 /** 550 * Subclasses may choose to implement this: for example, 551 * to change the interfaces exposed. 552 * <p>The default implementation is empty. 553 * @param proxyFactory a ProxyFactory that is already configured with 554 * TargetSource and interfaces and will be used to create the proxy 555 * immediately after this method returns 556 */ 557 protected void customizeProxyFactory(ProxyFactory proxyFactory) { 558 } 559 560 561 /** 562 * Return whether the given bean is to be proxied, what additional 563 * advices (e.g. AOP Alliance interceptors) and advisors to apply. 564 * @param beanClass the class of the bean to advise 565 * @param beanName the name of the bean 566 * @param customTargetSource the TargetSource returned by the 567 * {@link #getCustomTargetSource} method: may be ignored. 568 * Will be {@code null} if no custom target source is in use. 569 * @return an array of additional interceptors for the particular bean; 570 * or an empty array if no additional interceptors but just the common ones; 571 * or {@code null} if no proxy at all, not even with the common interceptors. 572 * See constants DO_NOT_PROXY and PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS. 573 * @throws BeansException in case of errors 574 * @see #DO_NOT_PROXY 575 * @see #PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS 576 */ 577 protected abstract Object[] getAdvicesAndAdvisorsForBean( 578 Class<?> beanClass, String beanName, TargetSource customTargetSource) throws BeansException; 579 580}