001/* 002 * Copyright 2002-2016 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.aspectj.annotation; 018 019import java.util.ArrayList; 020import java.util.List; 021import java.util.regex.Pattern; 022 023import org.springframework.aop.Advisor; 024import org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator; 025import org.springframework.beans.factory.ListableBeanFactory; 026import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 027import org.springframework.util.Assert; 028 029/** 030 * {@link AspectJAwareAdvisorAutoProxyCreator} subclass that processes all AspectJ 031 * annotation aspects in the current application context, as well as Spring Advisors. 032 * 033 * <p>Any AspectJ annotated classes will automatically be recognized, and their 034 * advice applied if Spring AOP's proxy-based model is capable of applying it. 035 * This covers method execution joinpoints. 036 * 037 * <p>If the <aop:include> element is used, only @AspectJ beans with names matched by 038 * an include pattern will be considered as defining aspects to use for Spring auto-proxying. 039 * 040 * <p>Processing of Spring Advisors follows the rules established in 041 * {@link org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator}. 042 * 043 * @author Rod Johnson 044 * @author Juergen Hoeller 045 * @since 2.0 046 * @see org.springframework.aop.aspectj.annotation.AspectJAdvisorFactory 047 */ 048@SuppressWarnings("serial") 049public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator { 050 051 private List<Pattern> includePatterns; 052 053 private AspectJAdvisorFactory aspectJAdvisorFactory; 054 055 private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder; 056 057 058 /** 059 * Set a list of regex patterns, matching eligible @AspectJ bean names. 060 * <p>Default is to consider all @AspectJ beans as eligible. 061 */ 062 public void setIncludePatterns(List<String> patterns) { 063 this.includePatterns = new ArrayList<Pattern>(patterns.size()); 064 for (String patternText : patterns) { 065 this.includePatterns.add(Pattern.compile(patternText)); 066 } 067 } 068 069 public void setAspectJAdvisorFactory(AspectJAdvisorFactory aspectJAdvisorFactory) { 070 Assert.notNull(aspectJAdvisorFactory, "AspectJAdvisorFactory must not be null"); 071 this.aspectJAdvisorFactory = aspectJAdvisorFactory; 072 } 073 074 @Override 075 protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) { 076 super.initBeanFactory(beanFactory); 077 if (this.aspectJAdvisorFactory == null) { 078 this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory); 079 } 080 this.aspectJAdvisorsBuilder = 081 new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory); 082 } 083 084 085 @Override 086 protected List<Advisor> findCandidateAdvisors() { 087 // Add all the Spring advisors found according to superclass rules. 088 List<Advisor> advisors = super.findCandidateAdvisors(); 089 // Build Advisors for all AspectJ aspects in the bean factory. 090 advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); 091 return advisors; 092 } 093 094 @Override 095 protected boolean isInfrastructureClass(Class<?> beanClass) { 096 // Previously we setProxyTargetClass(true) in the constructor, but that has too 097 // broad an impact. Instead we now override isInfrastructureClass to avoid proxying 098 // aspects. I'm not entirely happy with that as there is no good reason not 099 // to advise aspects, except that it causes advice invocation to go through a 100 // proxy, and if the aspect implements e.g the Ordered interface it will be 101 // proxied by that interface and fail at runtime as the advice method is not 102 // defined on the interface. We could potentially relax the restriction about 103 // not advising aspects in the future. 104 return (super.isInfrastructureClass(beanClass) || this.aspectJAdvisorFactory.isAspect(beanClass)); 105 } 106 107 /** 108 * Check whether the given aspect bean is eligible for auto-proxying. 109 * <p>If no <aop:include> elements were used then "includePatterns" will be 110 * {@code null} and all beans are included. If "includePatterns" is non-null, 111 * then one of the patterns must match. 112 */ 113 protected boolean isEligibleAspectBean(String beanName) { 114 if (this.includePatterns == null) { 115 return true; 116 } 117 else { 118 for (Pattern pattern : this.includePatterns) { 119 if (pattern.matcher(beanName).matches()) { 120 return true; 121 } 122 } 123 return false; 124 } 125 } 126 127 128 /** 129 * Subclass of BeanFactoryAspectJAdvisorsBuilderAdapter that delegates to 130 * surrounding AnnotationAwareAspectJAutoProxyCreator facilities. 131 */ 132 private class BeanFactoryAspectJAdvisorsBuilderAdapter extends BeanFactoryAspectJAdvisorsBuilder { 133 134 public BeanFactoryAspectJAdvisorsBuilderAdapter( 135 ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) { 136 137 super(beanFactory, advisorFactory); 138 } 139 140 @Override 141 protected boolean isEligibleBean(String beanName) { 142 return AnnotationAwareAspectJAutoProxyCreator.this.isEligibleAspectBean(beanName); 143 } 144 } 145 146}