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