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; 018 019import java.util.Map; 020import java.util.concurrent.ConcurrentHashMap; 021 022import org.springframework.aop.Advisor; 023import org.springframework.aop.support.AopUtils; 024import org.springframework.beans.factory.config.BeanPostProcessor; 025import org.springframework.lang.Nullable; 026 027/** 028 * Base class for {@link BeanPostProcessor} implementations that apply a 029 * Spring AOP {@link Advisor} to specific beans. 030 * 031 * @author Juergen Hoeller 032 * @since 3.2 033 */ 034@SuppressWarnings("serial") 035public abstract class AbstractAdvisingBeanPostProcessor extends ProxyProcessorSupport implements BeanPostProcessor { 036 037 @Nullable 038 protected Advisor advisor; 039 040 protected boolean beforeExistingAdvisors = false; 041 042 private final Map<Class<?>, Boolean> eligibleBeans = new ConcurrentHashMap<>(256); 043 044 045 /** 046 * Set whether this post-processor's advisor is supposed to apply before 047 * existing advisors when encountering a pre-advised object. 048 * <p>Default is "false", applying the advisor after existing advisors, i.e. 049 * as close as possible to the target method. Switch this to "true" in order 050 * for this post-processor's advisor to wrap existing advisors as well. 051 * <p>Note: Check the concrete post-processor's javadoc whether it possibly 052 * changes this flag by default, depending on the nature of its advisor. 053 */ 054 public void setBeforeExistingAdvisors(boolean beforeExistingAdvisors) { 055 this.beforeExistingAdvisors = beforeExistingAdvisors; 056 } 057 058 059 @Override 060 public Object postProcessBeforeInitialization(Object bean, String beanName) { 061 return bean; 062 } 063 064 @Override 065 public Object postProcessAfterInitialization(Object bean, String beanName) { 066 if (this.advisor == null || bean instanceof AopInfrastructureBean) { 067 // Ignore AOP infrastructure such as scoped proxies. 068 return bean; 069 } 070 071 if (bean instanceof Advised) { 072 Advised advised = (Advised) bean; 073 if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) { 074 // Add our local Advisor to the existing proxy's Advisor chain... 075 if (this.beforeExistingAdvisors) { 076 advised.addAdvisor(0, this.advisor); 077 } 078 else { 079 advised.addAdvisor(this.advisor); 080 } 081 return bean; 082 } 083 } 084 085 if (isEligible(bean, beanName)) { 086 ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName); 087 if (!proxyFactory.isProxyTargetClass()) { 088 evaluateProxyInterfaces(bean.getClass(), proxyFactory); 089 } 090 proxyFactory.addAdvisor(this.advisor); 091 customizeProxyFactory(proxyFactory); 092 return proxyFactory.getProxy(getProxyClassLoader()); 093 } 094 095 // No proxy needed. 096 return bean; 097 } 098 099 /** 100 * Check whether the given bean is eligible for advising with this 101 * post-processor's {@link Advisor}. 102 * <p>Delegates to {@link #isEligible(Class)} for target class checking. 103 * Can be overridden e.g. to specifically exclude certain beans by name. 104 * <p>Note: Only called for regular bean instances but not for existing 105 * proxy instances which implement {@link Advised} and allow for adding 106 * the local {@link Advisor} to the existing proxy's {@link Advisor} chain. 107 * For the latter, {@link #isEligible(Class)} is being called directly, 108 * with the actual target class behind the existing proxy (as determined 109 * by {@link AopUtils#getTargetClass(Object)}). 110 * @param bean the bean instance 111 * @param beanName the name of the bean 112 * @see #isEligible(Class) 113 */ 114 protected boolean isEligible(Object bean, String beanName) { 115 return isEligible(bean.getClass()); 116 } 117 118 /** 119 * Check whether the given class is eligible for advising with this 120 * post-processor's {@link Advisor}. 121 * <p>Implements caching of {@code canApply} results per bean target class. 122 * @param targetClass the class to check against 123 * @see AopUtils#canApply(Advisor, Class) 124 */ 125 protected boolean isEligible(Class<?> targetClass) { 126 Boolean eligible = this.eligibleBeans.get(targetClass); 127 if (eligible != null) { 128 return eligible; 129 } 130 if (this.advisor == null) { 131 return false; 132 } 133 eligible = AopUtils.canApply(this.advisor, targetClass); 134 this.eligibleBeans.put(targetClass, eligible); 135 return eligible; 136 } 137 138 /** 139 * Prepare a {@link ProxyFactory} for the given bean. 140 * <p>Subclasses may customize the handling of the target instance and in 141 * particular the exposure of the target class. The default introspection 142 * of interfaces for non-target-class proxies and the configured advisor 143 * will be applied afterwards; {@link #customizeProxyFactory} allows for 144 * late customizations of those parts right before proxy creation. 145 * @param bean the bean instance to create a proxy for 146 * @param beanName the corresponding bean name 147 * @return the ProxyFactory, initialized with this processor's 148 * {@link ProxyConfig} settings and the specified bean 149 * @since 4.2.3 150 * @see #customizeProxyFactory 151 */ 152 protected ProxyFactory prepareProxyFactory(Object bean, String beanName) { 153 ProxyFactory proxyFactory = new ProxyFactory(); 154 proxyFactory.copyFrom(this); 155 proxyFactory.setTarget(bean); 156 return proxyFactory; 157 } 158 159 /** 160 * Subclasses may choose to implement this: for example, 161 * to change the interfaces exposed. 162 * <p>The default implementation is empty. 163 * @param proxyFactory the ProxyFactory that is already configured with 164 * target, advisor and interfaces and will be used to create the proxy 165 * immediately after this method returns 166 * @since 4.2.3 167 * @see #prepareProxyFactory 168 */ 169 protected void customizeProxyFactory(ProxyFactory proxyFactory) { 170 } 171 172}