diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/AbstractAdvisingBeanPostProcessor.java b/spring-aop/src/main/java/org/springframework/aop/framework/AbstractAdvisingBeanPostProcessor.java new file mode 100644 index 0000000000..e671def56a --- /dev/null +++ b/spring-aop/src/main/java/org/springframework/aop/framework/AbstractAdvisingBeanPostProcessor.java @@ -0,0 +1,112 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.framework; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.aop.Advisor; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.core.Ordered; +import org.springframework.util.ClassUtils; + +/** + * Base class for {@link BeanPostProcessor} implementations that apply a + * Spring AOP {@link Advisor} to specific beans. + * + * @author Juergen Hoeller + * @since 3.2 + */ +public abstract class AbstractAdvisingBeanPostProcessor extends ProxyConfig + implements BeanPostProcessor, BeanClassLoaderAware, Ordered { + + protected Advisor advisor; + + private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + + /** + * This should run after all other post-processors, so that it can just add + * an advisor to existing proxies rather than double-proxy. + */ + private int order = Ordered.LOWEST_PRECEDENCE; + + private final Map eligibleBeans = new ConcurrentHashMap(); + + + public void setBeanClassLoader(ClassLoader beanClassLoader) { + this.beanClassLoader = beanClassLoader; + } + + public void setOrder(int order) { + this.order = order; + } + + public int getOrder() { + return this.order; + } + + + public Object postProcessBeforeInitialization(Object bean, String beanName) { + return bean; + } + + public Object postProcessAfterInitialization(Object bean, String beanName) { + if (bean instanceof AopInfrastructureBean) { + // Ignore AOP infrastructure such as scoped proxies. + return bean; + } + if (isEligible(bean, beanName)) { + if (bean instanceof Advised) { + ((Advised) bean).addAdvisor(0, this.advisor); + return bean; + } + else { + ProxyFactory proxyFactory = new ProxyFactory(bean); + // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig. + proxyFactory.copyFrom(this); + proxyFactory.addAdvisor(this.advisor); + return proxyFactory.getProxy(this.beanClassLoader); + } + } + else { + // No async proxy needed. + return bean; + } + } + + /** + * Check whether the given bean is eligible for advising with this + * post-processor's {@link Advisor}. + *

Implements caching of canApply results per bean name. + * @param bean the bean instance + * @param beanName the name of the bean + * @see AopUtils#canApply(Advisor, Class) + */ + protected boolean isEligible(Object bean, String beanName) { + Boolean eligible = this.eligibleBeans.get(beanName); + if (eligible != null) { + return eligible; + } + Class targetClass = AopUtils.getTargetClass(bean); + eligible = AopUtils.canApply(this.advisor, targetClass); + this.eligibleBeans.put(beanName, eligible); + return eligible; + } + +} diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationBeanPostProcessor.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationBeanPostProcessor.java index 77ad6786a5..7d175f1a78 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationBeanPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationBeanPostProcessor.java @@ -19,21 +19,11 @@ package org.springframework.scheduling.annotation; import java.lang.annotation.Annotation; import java.util.concurrent.Executor; -import org.springframework.aop.framework.Advised; -import org.springframework.aop.framework.AopInfrastructureBean; -import org.springframework.aop.framework.ProxyConfig; -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.aop.support.AopUtils; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.aop.framework.AbstractAdvisingBeanPostProcessor; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.core.Ordered; import org.springframework.core.task.TaskExecutor; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; /** * Bean post-processor that automatically applies asynchronous invocation @@ -55,26 +45,13 @@ import org.springframework.util.ClassUtils; * @see AsyncAnnotationAdvisor */ @SuppressWarnings("serial") -public class AsyncAnnotationBeanPostProcessor extends ProxyConfig - implements BeanPostProcessor, BeanClassLoaderAware, BeanFactoryAware, - InitializingBean, Ordered { +public class AsyncAnnotationBeanPostProcessor extends AbstractAdvisingBeanPostProcessor + implements BeanFactoryAware { private Class asyncAnnotationType; private Executor executor; - private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); - - private AsyncAnnotationAdvisor asyncAnnotationAdvisor; - - /** - * This should run after all other post-processors, so that it can just add - * an advisor to existing proxies rather than double-proxy. - */ - private int order = Ordered.LOWEST_PRECEDENCE; - - private BeanFactory beanFactory; - /** * Set the 'async' annotation type to be detected at either class or method @@ -97,59 +74,14 @@ public class AsyncAnnotationBeanPostProcessor extends ProxyConfig this.executor = executor; } - public void setBeanClassLoader(ClassLoader classLoader) { - this.beanClassLoader = classLoader; - } - - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = beanFactory; - } - - public void afterPropertiesSet() { - this.asyncAnnotationAdvisor = (this.executor != null ? + public void setBeanFactory(BeanFactory beanFactory) { + AsyncAnnotationAdvisor advisor = (this.executor != null ? new AsyncAnnotationAdvisor(this.executor) : new AsyncAnnotationAdvisor()); if (this.asyncAnnotationType != null) { - this.asyncAnnotationAdvisor.setAsyncAnnotationType(this.asyncAnnotationType); - } - this.asyncAnnotationAdvisor.setBeanFactory(this.beanFactory); - } - - public int getOrder() { - return this.order; - } - - public void setOrder(int order) { - this.order = order; - } - - - public Object postProcessBeforeInitialization(Object bean, String beanName) { - return bean; - } - - public Object postProcessAfterInitialization(Object bean, String beanName) { - if (bean instanceof AopInfrastructureBean) { - // Ignore AOP infrastructure such as scoped proxies. - return bean; - } - Class targetClass = AopUtils.getTargetClass(bean); - if (AopUtils.canApply(this.asyncAnnotationAdvisor, targetClass)) { - if (bean instanceof Advised) { - ((Advised) bean).addAdvisor(0, this.asyncAnnotationAdvisor); - return bean; - } - else { - ProxyFactory proxyFactory = new ProxyFactory(bean); - // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig. - proxyFactory.copyFrom(this); - proxyFactory.addAdvisor(this.asyncAnnotationAdvisor); - return proxyFactory.getProxy(this.beanClassLoader); - } - } - else { - // No async proxy needed. - return bean; + advisor.setAsyncAnnotationType(this.asyncAnnotationType); } + advisor.setBeanFactory(beanFactory); + this.advisor = advisor; } } diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.java index 531a984c98..9e4e9bdd2c 100644 --- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import org.aopalliance.aop.Advice; import org.springframework.aop.Advisor; import org.springframework.aop.Pointcut; +import org.springframework.aop.framework.AbstractAdvisingBeanPostProcessor; import org.springframework.aop.framework.Advised; import org.springframework.aop.framework.AopInfrastructureBean; import org.springframework.aop.framework.ProxyConfig; @@ -67,17 +68,12 @@ import org.springframework.validation.annotation.Validated; * @see org.hibernate.validator.method.MethodValidator */ @SuppressWarnings("serial") -public class MethodValidationPostProcessor extends ProxyConfig - implements BeanPostProcessor, BeanClassLoaderAware, Ordered, InitializingBean { +public class MethodValidationPostProcessor extends AbstractAdvisingBeanPostProcessor { private Class validatedAnnotationType = Validated.class; private Validator validator; - private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); - - private Advisor advisor; - /** * Set the 'validated' annotation type. @@ -110,17 +106,6 @@ public class MethodValidationPostProcessor extends ProxyConfig this.validator = validatorFactory.getValidator(); } - public void setBeanClassLoader(ClassLoader classLoader) { - this.beanClassLoader = classLoader; - } - - public int getOrder() { - // This should run after all other post-processors, so that it can just add - // an advisor to existing proxies rather than double-proxy. - return LOWEST_PRECEDENCE; - } - - public void afterPropertiesSet() { Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true); Advice advice = (this.validator != null ? new MethodValidationInterceptor(this.validator) : @@ -128,34 +113,4 @@ public class MethodValidationPostProcessor extends ProxyConfig this.advisor = new DefaultPointcutAdvisor(pointcut, advice); } - - public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - return bean; - } - - public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { - if (bean instanceof AopInfrastructureBean) { - // Ignore AOP infrastructure such as scoped proxies. - return bean; - } - Class targetClass = AopUtils.getTargetClass(bean); - if (AopUtils.canApply(this.advisor, targetClass)) { - if (bean instanceof Advised) { - ((Advised) bean).addAdvisor(this.advisor); - return bean; - } - else { - ProxyFactory proxyFactory = new ProxyFactory(bean); - // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig. - proxyFactory.copyFrom(this); - proxyFactory.addAdvisor(this.advisor); - return proxyFactory.getProxy(this.beanClassLoader); - } - } - else { - // This is not a repository. - return bean; - } - } - } diff --git a/spring-tx/src/main/java/org/springframework/dao/annotation/PersistenceExceptionTranslationPostProcessor.java b/spring-tx/src/main/java/org/springframework/dao/annotation/PersistenceExceptionTranslationPostProcessor.java index c4ee41ee53..e60638b20f 100644 --- a/spring-tx/src/main/java/org/springframework/dao/annotation/PersistenceExceptionTranslationPostProcessor.java +++ b/spring-tx/src/main/java/org/springframework/dao/annotation/PersistenceExceptionTranslationPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,21 +18,12 @@ package org.springframework.dao.annotation; import java.lang.annotation.Annotation; -import org.springframework.aop.framework.Advised; -import org.springframework.aop.framework.AopInfrastructureBean; -import org.springframework.aop.framework.ProxyConfig; -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.aop.support.AopUtils; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.aop.framework.AbstractAdvisingBeanPostProcessor; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.ListableBeanFactory; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.core.Ordered; import org.springframework.stereotype.Repository; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; /** * Bean post-processor that automatically applies persistence exception translation to any @@ -67,15 +58,11 @@ import org.springframework.util.ClassUtils; * @see org.springframework.dao.support.PersistenceExceptionTranslator */ @SuppressWarnings("serial") -public class PersistenceExceptionTranslationPostProcessor extends ProxyConfig - implements BeanPostProcessor, BeanClassLoaderAware, BeanFactoryAware, Ordered { +public class PersistenceExceptionTranslationPostProcessor extends AbstractAdvisingBeanPostProcessor + implements BeanFactoryAware { private Class repositoryAnnotationType = Repository.class; - private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); - - private PersistenceExceptionTranslationAdvisor persistenceExceptionTranslationAdvisor; - /** * Set the 'repository' annotation type. @@ -90,53 +77,13 @@ public class PersistenceExceptionTranslationPostProcessor extends ProxyConfig this.repositoryAnnotationType = repositoryAnnotationType; } - public void setBeanClassLoader(ClassLoader classLoader) { - this.beanClassLoader = classLoader; - } - - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + public void setBeanFactory(BeanFactory beanFactory) { if (!(beanFactory instanceof ListableBeanFactory)) { throw new IllegalArgumentException( "Cannot use PersistenceExceptionTranslator autodetection without ListableBeanFactory"); } - this.persistenceExceptionTranslationAdvisor = new PersistenceExceptionTranslationAdvisor( + this.advisor = new PersistenceExceptionTranslationAdvisor( (ListableBeanFactory) beanFactory, this.repositoryAnnotationType); } - public int getOrder() { - // This should run after all other post-processors, so that it can just add - // an advisor to existing proxies rather than double-proxy. - return LOWEST_PRECEDENCE; - } - - - public Object postProcessBeforeInitialization(Object bean, String beanName) { - return bean; - } - - public Object postProcessAfterInitialization(Object bean, String beanName) { - if (bean instanceof AopInfrastructureBean) { - // Ignore AOP infrastructure such as scoped proxies. - return bean; - } - Class targetClass = AopUtils.getTargetClass(bean); - if (AopUtils.canApply(this.persistenceExceptionTranslationAdvisor, targetClass)) { - if (bean instanceof Advised) { - ((Advised) bean).addAdvisor(this.persistenceExceptionTranslationAdvisor); - return bean; - } - else { - ProxyFactory proxyFactory = new ProxyFactory(bean); - // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig. - proxyFactory.copyFrom(this); - proxyFactory.addAdvisor(this.persistenceExceptionTranslationAdvisor); - return proxyFactory.getProxy(this.beanClassLoader); - } - } - else { - // This is not a repository. - return bean; - } - } - }