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