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.Collections; 020import java.util.LinkedList; 021import java.util.List; 022import java.util.Map; 023import java.util.concurrent.ConcurrentHashMap; 024 025import org.aspectj.lang.reflect.PerClauseKind; 026 027import org.springframework.aop.Advisor; 028import org.springframework.beans.factory.BeanFactoryUtils; 029import org.springframework.beans.factory.ListableBeanFactory; 030import org.springframework.util.Assert; 031 032/** 033 * Helper for retrieving @AspectJ beans from a BeanFactory and building 034 * Spring Advisors based on them, for use with auto-proxying. 035 * 036 * @author Juergen Hoeller 037 * @since 2.0.2 038 * @see AnnotationAwareAspectJAutoProxyCreator 039 */ 040public class BeanFactoryAspectJAdvisorsBuilder { 041 042 private final ListableBeanFactory beanFactory; 043 044 private final AspectJAdvisorFactory advisorFactory; 045 046 private volatile List<String> aspectBeanNames; 047 048 private final Map<String, List<Advisor>> advisorsCache = new ConcurrentHashMap<String, List<Advisor>>(); 049 050 private final Map<String, MetadataAwareAspectInstanceFactory> aspectFactoryCache = 051 new ConcurrentHashMap<String, MetadataAwareAspectInstanceFactory>(); 052 053 054 /** 055 * Create a new BeanFactoryAspectJAdvisorsBuilder for the given BeanFactory. 056 * @param beanFactory the ListableBeanFactory to scan 057 */ 058 public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory) { 059 this(beanFactory, new ReflectiveAspectJAdvisorFactory(beanFactory)); 060 } 061 062 /** 063 * Create a new BeanFactoryAspectJAdvisorsBuilder for the given BeanFactory. 064 * @param beanFactory the ListableBeanFactory to scan 065 * @param advisorFactory the AspectJAdvisorFactory to build each Advisor with 066 */ 067 public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) { 068 Assert.notNull(beanFactory, "ListableBeanFactory must not be null"); 069 Assert.notNull(advisorFactory, "AspectJAdvisorFactory must not be null"); 070 this.beanFactory = beanFactory; 071 this.advisorFactory = advisorFactory; 072 } 073 074 075 /** 076 * Look for AspectJ-annotated aspect beans in the current bean factory, 077 * and return to a list of Spring AOP Advisors representing them. 078 * <p>Creates a Spring Advisor for each AspectJ advice method. 079 * @return the list of {@link org.springframework.aop.Advisor} beans 080 * @see #isEligibleBean 081 */ 082 public List<Advisor> buildAspectJAdvisors() { 083 List<String> aspectNames = this.aspectBeanNames; 084 085 if (aspectNames == null) { 086 synchronized (this) { 087 aspectNames = this.aspectBeanNames; 088 if (aspectNames == null) { 089 List<Advisor> advisors = new LinkedList<Advisor>(); 090 aspectNames = new LinkedList<String>(); 091 String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( 092 this.beanFactory, Object.class, true, false); 093 for (String beanName : beanNames) { 094 if (!isEligibleBean(beanName)) { 095 continue; 096 } 097 // We must be careful not to instantiate beans eagerly as in this case they 098 // would be cached by the Spring container but would not have been weaved. 099 Class<?> beanType = this.beanFactory.getType(beanName); 100 if (beanType == null) { 101 continue; 102 } 103 if (this.advisorFactory.isAspect(beanType)) { 104 aspectNames.add(beanName); 105 AspectMetadata amd = new AspectMetadata(beanType, beanName); 106 if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { 107 MetadataAwareAspectInstanceFactory factory = 108 new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); 109 List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory); 110 if (this.beanFactory.isSingleton(beanName)) { 111 this.advisorsCache.put(beanName, classAdvisors); 112 } 113 else { 114 this.aspectFactoryCache.put(beanName, factory); 115 } 116 advisors.addAll(classAdvisors); 117 } 118 else { 119 // Per target or per this. 120 if (this.beanFactory.isSingleton(beanName)) { 121 throw new IllegalArgumentException("Bean with name '" + beanName + 122 "' is a singleton, but aspect instantiation model is not singleton"); 123 } 124 MetadataAwareAspectInstanceFactory factory = 125 new PrototypeAspectInstanceFactory(this.beanFactory, beanName); 126 this.aspectFactoryCache.put(beanName, factory); 127 advisors.addAll(this.advisorFactory.getAdvisors(factory)); 128 } 129 } 130 } 131 this.aspectBeanNames = aspectNames; 132 return advisors; 133 } 134 } 135 } 136 137 if (aspectNames.isEmpty()) { 138 return Collections.emptyList(); 139 } 140 List<Advisor> advisors = new LinkedList<Advisor>(); 141 for (String aspectName : aspectNames) { 142 List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName); 143 if (cachedAdvisors != null) { 144 advisors.addAll(cachedAdvisors); 145 } 146 else { 147 MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName); 148 advisors.addAll(this.advisorFactory.getAdvisors(factory)); 149 } 150 } 151 return advisors; 152 } 153 154 /** 155 * Return whether the aspect bean with the given name is eligible. 156 * @param beanName the name of the aspect bean 157 * @return whether the bean is eligible 158 */ 159 protected boolean isEligibleBean(String beanName) { 160 return true; 161 } 162 163}