1 /* 2 * Copyright 2002-2010 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.springframework.aop.aspectj.annotation; 18 19 import java.lang.reflect.Method; 20 21 import org.aopalliance.aop.Advice; 22 import org.aspectj.lang.reflect.PerClauseKind; 23 24 import org.springframework.aop.Pointcut; 25 import org.springframework.aop.aspectj.AspectJExpressionPointcut; 26 import org.springframework.aop.aspectj.AspectJPrecedenceInformation; 27 import org.springframework.aop.aspectj.InstantiationModelAwarePointcutAdvisor; 28 import org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory.AspectJAnnotation; 29 import org.springframework.aop.support.DynamicMethodMatcherPointcut; 30 import org.springframework.aop.support.Pointcuts; 31 32 /** 33 * Internal implementation of AspectJPointcutAdvisor. 34 * Note that there will be one instance of this advisor for each target method. 35 * 36 * @author Rod Johnson 37 * @author Juergen Hoeller 38 * @since 2.0 39 */ 40 class InstantiationModelAwarePointcutAdvisorImpl 41 implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation { 42 43 private final AspectJExpressionPointcut declaredPointcut; 44 45 private Pointcut pointcut; 46 47 private final MetadataAwareAspectInstanceFactory aspectInstanceFactory; 48 49 private final Method method; 50 51 private final boolean lazy; 52 53 private final AspectJAdvisorFactory atAspectJAdvisorFactory; 54 55 private Advice instantiatedAdvice; 56 57 private int declarationOrder; 58 59 private String aspectName; 60 61 private Boolean isBeforeAdvice; 62 63 private Boolean isAfterAdvice; 64 65 InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp, MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName)66 public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp, 67 MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName) { 68 69 this.declaredPointcut = ajexp; 70 this.method = method; 71 this.atAspectJAdvisorFactory = af; 72 this.aspectInstanceFactory = aif; 73 this.declarationOrder = declarationOrderInAspect; 74 this.aspectName = aspectName; 75 76 if (aif.getAspectMetadata().isLazilyInstantiated()) { 77 // Static part of the pointcut is a lazy type. 78 Pointcut preInstantiationPointcut = 79 Pointcuts.union(aif.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut); 80 81 // Make it dynamic: must mutate from pre-instantiation to post-instantiation state. 82 // If it's not a dynamic pointcut, it may be optimized out 83 // by the Spring AOP infrastructure after the first evaluation. 84 this.pointcut = new PerTargetInstantiationModelPointcut(this.declaredPointcut, preInstantiationPointcut, aif); 85 this.lazy = true; 86 } 87 else { 88 // A singleton aspect. 89 this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut); 90 this.pointcut = declaredPointcut; 91 this.lazy = false; 92 } 93 } 94 95 96 /** 97 * The pointcut for Spring AOP to use. Actual behaviour of the pointcut will change 98 * depending on the state of the advice. 99 */ getPointcut()100 public Pointcut getPointcut() { 101 return this.pointcut; 102 } 103 104 /** 105 * This is only of interest for Spring AOP: AspectJ instantiation semantics 106 * are much richer. In AspectJ terminology, all a return of <code>true</code> 107 * means here is that the aspect is not a SINGLETON. 108 */ isPerInstance()109 public boolean isPerInstance() { 110 return (getAspectMetadata().getAjType().getPerClause().getKind() != PerClauseKind.SINGLETON); 111 } 112 113 /** 114 * Return the AspectJ AspectMetadata for this advisor. 115 */ getAspectMetadata()116 public AspectMetadata getAspectMetadata() { 117 return this.aspectInstanceFactory.getAspectMetadata(); 118 } 119 120 /** 121 * Lazily instantiate advice if necessary. 122 */ getAdvice()123 public synchronized Advice getAdvice() { 124 if (this.instantiatedAdvice == null) { 125 this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut); 126 } 127 return this.instantiatedAdvice; 128 } 129 isLazy()130 public boolean isLazy() { 131 return this.lazy; 132 } 133 isAdviceInstantiated()134 public synchronized boolean isAdviceInstantiated() { 135 return (this.instantiatedAdvice != null); 136 } 137 138 instantiateAdvice(AspectJExpressionPointcut pcut)139 private Advice instantiateAdvice(AspectJExpressionPointcut pcut) { 140 return this.atAspectJAdvisorFactory.getAdvice( 141 this.method, pcut, this.aspectInstanceFactory, this.declarationOrder, this.aspectName); 142 } 143 getAspectInstanceFactory()144 public MetadataAwareAspectInstanceFactory getAspectInstanceFactory() { 145 return this.aspectInstanceFactory; 146 } 147 getDeclaredPointcut()148 public AspectJExpressionPointcut getDeclaredPointcut() { 149 return this.declaredPointcut; 150 } 151 getOrder()152 public int getOrder() { 153 return this.aspectInstanceFactory.getOrder(); 154 } 155 getAspectName()156 public String getAspectName() { 157 return this.aspectName; 158 } 159 getDeclarationOrder()160 public int getDeclarationOrder() { 161 return this.declarationOrder; 162 } 163 isBeforeAdvice()164 public boolean isBeforeAdvice() { 165 if (this.isBeforeAdvice == null) { 166 determineAdviceType(); 167 } 168 return this.isBeforeAdvice; 169 } 170 isAfterAdvice()171 public boolean isAfterAdvice() { 172 if (this.isAfterAdvice == null) { 173 determineAdviceType(); 174 } 175 return this.isAfterAdvice; 176 } 177 178 /** 179 * Duplicates some logic from getAdvice, but importantly does not force 180 * creation of the advice. 181 */ determineAdviceType()182 private void determineAdviceType() { 183 AspectJAnnotation<?> aspectJAnnotation = 184 AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(this.method); 185 if (aspectJAnnotation == null) { 186 this.isBeforeAdvice = false; 187 this.isAfterAdvice = false; 188 } 189 else { 190 switch (aspectJAnnotation.getAnnotationType()) { 191 case AtAfter: 192 case AtAfterReturning: 193 case AtAfterThrowing: 194 this.isAfterAdvice = true; 195 this.isBeforeAdvice = false; 196 break; 197 case AtAround: 198 case AtPointcut: 199 this.isAfterAdvice = false; 200 this.isBeforeAdvice = false; 201 break; 202 case AtBefore: 203 this.isAfterAdvice = false; 204 this.isBeforeAdvice = true; 205 } 206 } 207 } 208 209 210 @Override toString()211 public String toString() { 212 return "InstantiationModelAwarePointcutAdvisor: expression [" + getDeclaredPointcut().getExpression() + 213 "]; advice method [" + this.method + "]; perClauseKind=" + 214 this.aspectInstanceFactory.getAspectMetadata().getAjType().getPerClause().getKind(); 215 216 } 217 218 219 /** 220 * Pointcut implementation that changes its behaviour when the advice is instantiated. 221 * Note that this is a <i>dynamic</i> pointcut. Otherwise it might 222 * be optimized out if it does not at first match statically. 223 */ 224 private class PerTargetInstantiationModelPointcut extends DynamicMethodMatcherPointcut { 225 226 private final AspectJExpressionPointcut declaredPointcut; 227 228 private final Pointcut preInstantiationPointcut; 229 230 private LazySingletonAspectInstanceFactoryDecorator aspectInstanceFactory; 231 PerTargetInstantiationModelPointcut(AspectJExpressionPointcut declaredPointcut, Pointcut preInstantiationPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory)232 private PerTargetInstantiationModelPointcut(AspectJExpressionPointcut declaredPointcut, 233 Pointcut preInstantiationPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory) { 234 this.declaredPointcut = declaredPointcut; 235 this.preInstantiationPointcut = preInstantiationPointcut; 236 if (aspectInstanceFactory instanceof LazySingletonAspectInstanceFactoryDecorator) { 237 this.aspectInstanceFactory = (LazySingletonAspectInstanceFactoryDecorator) aspectInstanceFactory; 238 } 239 } 240 241 @Override matches(Method method, Class targetClass)242 public boolean matches(Method method, Class targetClass) { 243 // We're either instantiated and matching on declared pointcut, or uninstantiated matching on either pointcut 244 return (isAspectMaterialized() && this.declaredPointcut.matches(method, targetClass)) || 245 this.preInstantiationPointcut.getMethodMatcher().matches(method, targetClass); 246 } 247 matches(Method method, Class targetClass, Object[] args)248 public boolean matches(Method method, Class targetClass, Object[] args) { 249 // This can match only on declared pointcut. 250 return (isAspectMaterialized() && this.declaredPointcut.matches(method, targetClass)); 251 } 252 isAspectMaterialized()253 private boolean isAspectMaterialized() { 254 return (this.aspectInstanceFactory == null || this.aspectInstanceFactory.isMaterialized()); 255 } 256 } 257 258 } 259