先看看 AspectJExpressionPointcutAdvisor 的类图
再了解一下切点(Pointcut)表达式,它指定触发advice的方法,可以精确到返回参数,参数类型,方法名
1 package concert; 2 3 public interface Performance { 4 void perform(); 5 }
AspectJExpressionPointcutAdvisor 源码,官方文档解释说这是可以用于任何AspectJ切入点表达式的 Spring AOP Advisor。
1 @SuppressWarnings("serial") 2 public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdvisor implements BeanFactoryAware { 3 4 private final AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); // AspectJ表达式切点匹配器 5 6 7 public void setExpression(@Nullable String expression) { 8 this.pointcut.setExpression(expression); 9 } 10 11 @Nullable 12 public String getExpression() { 13 return this.pointcut.getExpression(); 14 } 15 16 public void setLocation(@Nullable String location) { 17 this.pointcut.setLocation(location); 18 } 19 20 @Nullable 21 public String getLocation() { 22 return this.pointcut.getLocation(); 23 } 24 25 public void setParameterNames(String... names) { 26 this.pointcut.setParameterNames(names); 27 } 28 29 public void setParameterTypes(Class<?>... types) { 30 this.pointcut.setParameterTypes(types); 31 } 32 33 @Override 34 public void setBeanFactory(BeanFactory beanFactory) { 35 this.pointcut.setBeanFactory(beanFactory); 36 } 37 38 @Override 39 public Pointcut getPointcut() { 40 return this.pointcut; 41 } 42 43 }
再看看 AspectJExpressionPointcutAdvisor 的抽象父类 AbstractGenericPointcutAdvisor 的源码
1 @SuppressWarnings("serial") 2 public abstract class AbstractGenericPointcutAdvisor extends AbstractPointcutAdvisor { 3 4 private Advice advice = EMPTY_ADVICE; // Advisor接口中定义的占位符 5 6 7 /** 8 * Specify the advice that this advisor should apply. 9 */ 10 public void setAdvice(Advice advice) { 11 this.advice = advice; 12 } 13 14 @Override 15 public Advice getAdvice() { 16 return this.advice; 17 } 18 19 20 @Override 21 public String toString() { 22 return getClass().getName() + ": advice [" + getAdvice() + "]"; 23 } 24 25 }
看完源码后,可以了解到一个 AspectJExpressionPointcutAdvisor 是用来处理对应 AspectJ 的 advice 和切点的,可以在代码中看见有advice的设置和获取、切点表达式的一些处理、设置切点的Bean工厂,还有获取该切点。该 AspectJExpressionPointcutAdvisor 创建了一个 AspectJExpressionPointcut,它们之间的关系是一对一的组合关系,如同字面意思,AspectJExpressionPointcut 与切点表达式有关。
下面是 AspectJExpressionPointcut 的类图
AspectJExpressionPointcut 的源码(过长折叠起来了)
1 public class AspectJExpressionPointcut extends AbstractExpressionPointcut implements ClassFilter, IntroductionAwareMethodMatcher, BeanFactoryAware { 2 private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet(); 3 private static final Log logger; 4 @Nullable 5 private Class<?> pointcutDeclarationScope; 6 private String[] pointcutParameterNames = new String[0]; 7 private Class<?>[] pointcutParameterTypes = new Class[0]; 8 @Nullable 9 private BeanFactory beanFactory; 10 @Nullable 11 private transient ClassLoader pointcutClassLoader; 12 @Nullable 13 private transient PointcutExpression pointcutExpression; 14 private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap(32); 15 16 public AspectJExpressionPointcut() { 17 } 18 19 public AspectJExpressionPointcut(Class<?> declarationScope, String[] paramNames, Class<?>[] paramTypes) { 20 this.pointcutDeclarationScope = declarationScope; 21 if (paramNames.length != paramTypes.length) { 22 throw new IllegalStateException("Number of pointcut parameter names must match number of pointcut parameter types"); 23 } else { 24 this.pointcutParameterNames = paramNames; 25 this.pointcutParameterTypes = paramTypes; 26 } 27 } 28 29 public void setPointcutDeclarationScope(Class<?> pointcutDeclarationScope) { 30 this.pointcutDeclarationScope = pointcutDeclarationScope; 31 } 32 33 public void setParameterNames(String... names) { 34 this.pointcutParameterNames = names; 35 } 36 37 public void setParameterTypes(Class<?>... types) { 38 this.pointcutParameterTypes = types; 39 } 40 41 public void setBeanFactory(BeanFactory beanFactory) { 42 this.beanFactory = beanFactory; 43 } 44 45 public ClassFilter getClassFilter() { 46 this.obtainPointcutExpression(); 47 return this; 48 } 49 50 public MethodMatcher getMethodMatcher() { 51 this.obtainPointcutExpression(); 52 return this; 53 } 54 55 private PointcutExpression obtainPointcutExpression() { 56 if (this.getExpression() == null) { 57 throw new IllegalStateException("Must set property ‘expression‘ before attempting to match"); 58 } else { 59 if (this.pointcutExpression == null) { 60 this.pointcutClassLoader = this.determinePointcutClassLoader(); 61 this.pointcutExpression = this.buildPointcutExpression(this.pointcutClassLoader); 62 } 63 64 return this.pointcutExpression; 65 } 66 } 67 68 @Nullable 69 private ClassLoader determinePointcutClassLoader() { 70 if (this.beanFactory instanceof ConfigurableBeanFactory) { 71 return ((ConfigurableBeanFactory)this.beanFactory).getBeanClassLoader(); 72 } else { 73 return this.pointcutDeclarationScope != null ? this.pointcutDeclarationScope.getClassLoader() : ClassUtils.getDefaultClassLoader(); 74 } 75 } 76 77 private PointcutExpression buildPointcutExpression(@Nullable ClassLoader classLoader) { 78 PointcutParser parser = this.initializePointcutParser(classLoader); 79 PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length]; 80 81 for(int i = 0; i < pointcutParameters.length; ++i) { 82 pointcutParameters[i] = parser.createPointcutParameter(this.pointcutParameterNames[i], this.pointcutParameterTypes[i]); 83 } 84 85 return parser.parsePointcutExpression(this.replaceBooleanOperators(this.resolveExpression()), this.pointcutDeclarationScope, pointcutParameters); 86 } 87 88 private String resolveExpression() { 89 String expression = this.getExpression(); 90 Assert.state(expression != null, "No expression set"); 91 return expression; 92 } 93 94 private PointcutParser initializePointcutParser(@Nullable ClassLoader classLoader) { 95 PointcutParser parser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, classLoader); 96 parser.registerPointcutDesignatorHandler(new AspectJExpressionPointcut.BeanPointcutDesignatorHandler()); 97 return parser; 98 } 99 100 private String replaceBooleanOperators(String pcExpr) { 101 String result = StringUtils.replace(pcExpr, " and ", " && "); 102 result = StringUtils.replace(result, " or ", " || "); 103 result = StringUtils.replace(result, " not ", " ! "); 104 return result; 105 } 106 107 public PointcutExpression getPointcutExpression() { 108 return this.obtainPointcutExpression(); 109 } 110 111 public boolean matches(Class<?> targetClass) { 112 PointcutExpression pointcutExpression = this.obtainPointcutExpression(); 113 114 try { 115 try { 116 return pointcutExpression.couldMatchJoinPointsInType(targetClass); 117 } catch (ReflectionWorldException var5) { 118 logger.debug("PointcutExpression matching rejected target class - trying fallback expression", var5); 119 PointcutExpression fallbackExpression = this.getFallbackPointcutExpression(targetClass); 120 if (fallbackExpression != null) { 121 return fallbackExpression.couldMatchJoinPointsInType(targetClass); 122 } 123 } 124 } catch (Throwable var6) { 125 logger.debug("PointcutExpression matching rejected target class", var6); 126 } 127 128 return false; 129 } 130 131 public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) { 132 this.obtainPointcutExpression(); 133 ShadowMatch shadowMatch = this.getTargetShadowMatch(method, targetClass); 134 if (shadowMatch.alwaysMatches()) { 135 return true; 136 } else if (shadowMatch.neverMatches()) { 137 return false; 138 } else if (hasIntroductions) { 139 return true; 140 } else { 141 RuntimeTestWalker walker = this.getRuntimeTestWalker(shadowMatch); 142 return !walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass); 143 } 144 } 145 146 public boolean matches(Method method, Class<?> targetClass) { 147 return this.matches(method, targetClass, false); 148 } 149 150 public boolean isRuntime() { 151 return this.obtainPointcutExpression().mayNeedDynamicTest(); 152 } 153 154 public boolean matches(Method method, Class<?> targetClass, Object... args) { 155 this.obtainPointcutExpression(); 156 ShadowMatch shadowMatch = this.getTargetShadowMatch(method, targetClass); 157 ProxyMethodInvocation pmi = null; 158 Object targetObject = null; 159 Object thisObject = null; 160 161 try { 162 MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation(); 163 targetObject = mi.getThis(); 164 if (!(mi instanceof ProxyMethodInvocation)) { 165 throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi); 166 } 167 168 pmi = (ProxyMethodInvocation)mi; 169 thisObject = pmi.getProxy(); 170 } catch (IllegalStateException var11) { 171 if (logger.isDebugEnabled()) { 172 logger.debug("Could not access current invocation - matching with limited context: " + var11); 173 } 174 } 175 176 try { 177 JoinPointMatch joinPointMatch = shadowMatch.matchesJoinPoint(thisObject, targetObject, args); 178 if (pmi != null && thisObject != null) { 179 RuntimeTestWalker originalMethodResidueTest = this.getRuntimeTestWalker(this.getShadowMatch(method, method)); 180 if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) { 181 return false; 182 } 183 184 if (joinPointMatch.matches()) { 185 this.bindParameters(pmi, joinPointMatch); 186 } 187 } 188 189 return joinPointMatch.matches(); 190 } catch (Throwable var10) { 191 if (logger.isDebugEnabled()) { 192 logger.debug("Failed to evaluate join point for arguments " + Arrays.asList(args) + " - falling back to non-match", var10); 193 } 194 195 return false; 196 } 197 } 198 199 @Nullable 200 protected String getCurrentProxiedBeanName() { 201 return ProxyCreationContext.getCurrentProxiedBeanName(); 202 } 203 204 @Nullable 205 private PointcutExpression getFallbackPointcutExpression(Class<?> targetClass) { 206 try { 207 ClassLoader classLoader = targetClass.getClassLoader(); 208 if (classLoader != null && classLoader != this.pointcutClassLoader) { 209 return this.buildPointcutExpression(classLoader); 210 } 211 } catch (Throwable var3) { 212 logger.debug("Failed to create fallback PointcutExpression", var3); 213 } 214 215 return null; 216 } 217 218 private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) { 219 return shadowMatch instanceof AspectJExpressionPointcut.DefensiveShadowMatch ? new RuntimeTestWalker(((AspectJExpressionPointcut.DefensiveShadowMatch)shadowMatch).primary) : new RuntimeTestWalker(shadowMatch); 220 } 221 222 private void bindParameters(ProxyMethodInvocation invocation, JoinPointMatch jpm) { 223 invocation.setUserAttribute(this.resolveExpression(), jpm); 224 } 225 226 private ShadowMatch getTargetShadowMatch(Method method, Class<?> targetClass) { 227 Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass); 228 if (targetMethod.getDeclaringClass().isInterface()) { 229 Set<Class<?>> ifcs = ClassUtils.getAllInterfacesForClassAsSet(targetClass); 230 if (ifcs.size() > 1) { 231 try { 232 Class<?> compositeInterface = ClassUtils.createCompositeInterface(ClassUtils.toClassArray(ifcs), targetClass.getClassLoader()); 233 targetMethod = ClassUtils.getMostSpecificMethod(targetMethod, compositeInterface); 234 } catch (IllegalArgumentException var6) { 235 } 236 } 237 } 238 239 return this.getShadowMatch(targetMethod, method); 240 } 241 242 private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) { 243 ShadowMatch shadowMatch = (ShadowMatch)this.shadowMatchCache.get(targetMethod); 244 if (shadowMatch == null) { 245 synchronized(this.shadowMatchCache) { 246 PointcutExpression fallbackExpression = null; 247 shadowMatch = (ShadowMatch)this.shadowMatchCache.get(targetMethod); 248 if (shadowMatch == null) { 249 Method methodToMatch = targetMethod; 250 251 try { 252 try { 253 shadowMatch = this.obtainPointcutExpression().matchesMethodExecution(methodToMatch); 254 } catch (ReflectionWorldException var13) { 255 try { 256 fallbackExpression = this.getFallbackPointcutExpression(methodToMatch.getDeclaringClass()); 257 if (fallbackExpression != null) { 258 shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch); 259 } 260 } catch (ReflectionWorldException var12) { 261 fallbackExpression = null; 262 } 263 } 264 265 if (targetMethod != originalMethod && (shadowMatch == null || ((ShadowMatch)shadowMatch).neverMatches() && Proxy.isProxyClass(targetMethod.getDeclaringClass()))) { 266 methodToMatch = originalMethod; 267 268 try { 269 shadowMatch = this.obtainPointcutExpression().matchesMethodExecution(methodToMatch); 270 } catch (ReflectionWorldException var11) { 271 try { 272 fallbackExpression = this.getFallbackPointcutExpression(methodToMatch.getDeclaringClass()); 273 if (fallbackExpression != null) { 274 shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch); 275 } 276 } catch (ReflectionWorldException var10) { 277 fallbackExpression = null; 278 } 279 } 280 } 281 } catch (Throwable var14) { 282 logger.debug("PointcutExpression matching rejected target method", var14); 283 fallbackExpression = null; 284 } 285 286 if (shadowMatch == null) { 287 shadowMatch = new ShadowMatchImpl(FuzzyBoolean.NO, (Test)null, (ExposedState)null, (PointcutParameter[])null); 288 } else if (((ShadowMatch)shadowMatch).maybeMatches() && fallbackExpression != null) { 289 shadowMatch = new AspectJExpressionPointcut.DefensiveShadowMatch((ShadowMatch)shadowMatch, fallbackExpression.matchesMethodExecution(methodToMatch)); 290 } 291 292 this.shadowMatchCache.put(targetMethod, shadowMatch); 293 } 294 } 295 } 296 297 return (ShadowMatch)shadowMatch; 298 } 299 300 public boolean equals(Object other) { 301 if (this == other) { 302 return true; 303 } else if (!(other instanceof AspectJExpressionPointcut)) { 304 return false; 305 } else { 306 AspectJExpressionPointcut otherPc = (AspectJExpressionPointcut)other; 307 return ObjectUtils.nullSafeEquals(this.getExpression(), otherPc.getExpression()) && ObjectUtils.nullSafeEquals(this.pointcutDeclarationScope, otherPc.pointcutDeclarationScope) && ObjectUtils.nullSafeEquals(this.pointcutParameterNames, otherPc.pointcutParameterNames) && ObjectUtils.nullSafeEquals(this.pointcutParameterTypes, otherPc.pointcutParameterTypes); 308 } 309 } 310 311 public int hashCode() { 312 int hashCode = ObjectUtils.nullSafeHashCode(this.getExpression()); 313 hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutDeclarationScope); 314 hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutParameterNames); 315 hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutParameterTypes); 316 return hashCode; 317 } 318 319 public String toString() { 320 StringBuilder sb = new StringBuilder(); 321 sb.append("AspectJExpressionPointcut: "); 322 sb.append("("); 323 324 for(int i = 0; i < this.pointcutParameterTypes.length; ++i) { 325 sb.append(this.pointcutParameterTypes[i].getName()); 326 sb.append(" "); 327 sb.append(this.pointcutParameterNames[i]); 328 if (i + 1 < this.pointcutParameterTypes.length) { 329 sb.append(", "); 330 } 331 } 332 333 sb.append(")"); 334 sb.append(" "); 335 if (this.getExpression() != null) { 336 sb.append(this.getExpression()); 337 } else { 338 sb.append("<pointcut expression not set>"); 339 } 340 341 return sb.toString(); 342 } 343 344 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { 345 ois.defaultReadObject(); 346 this.shadowMatchCache = new ConcurrentHashMap(32); 347 } 348 349 static { 350 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION); 351 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS); 352 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE); 353 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS); 354 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET); 355 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN); 356 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION); 357 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN); 358 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS); 359 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET); 360 logger = LogFactory.getLog(AspectJExpressionPointcut.class); 361 } 362 363 private static class DefensiveShadowMatch implements ShadowMatch { 364 private final ShadowMatch primary; 365 private final ShadowMatch other; 366 367 public DefensiveShadowMatch(ShadowMatch primary, ShadowMatch other) { 368 this.primary = primary; 369 this.other = other; 370 } 371 372 public boolean alwaysMatches() { 373 return this.primary.alwaysMatches(); 374 } 375 376 public boolean maybeMatches() { 377 return this.primary.maybeMatches(); 378 } 379 380 public boolean neverMatches() { 381 return this.primary.neverMatches(); 382 } 383 384 public JoinPointMatch matchesJoinPoint(Object thisObject, Object targetObject, Object[] args) { 385 try { 386 return this.primary.matchesJoinPoint(thisObject, targetObject, args); 387 } catch (ReflectionWorldException var5) { 388 return this.other.matchesJoinPoint(thisObject, targetObject, args); 389 } 390 } 391 392 public void setMatchingContext(MatchingContext aMatchContext) { 393 this.primary.setMatchingContext(aMatchContext); 394 this.other.setMatchingContext(aMatchContext); 395 } 396 } 397 398 private class BeanContextMatcher implements ContextBasedMatcher { 399 private final NamePattern expressionPattern; 400 401 public BeanContextMatcher(String expression) { 402 this.expressionPattern = new NamePattern(expression); 403 } 404 405 /** @deprecated */ 406 @Deprecated 407 public boolean couldMatchJoinPointsInType(Class someClass) { 408 return this.contextMatch(someClass) == org.aspectj.weaver.tools.FuzzyBoolean.YES; 409 } 410 411 /** @deprecated */ 412 @Deprecated 413 public boolean couldMatchJoinPointsInType(Class someClass, MatchingContext context) { 414 return this.contextMatch(someClass) == org.aspectj.weaver.tools.FuzzyBoolean.YES; 415 } 416 417 public boolean matchesDynamically(MatchingContext context) { 418 return true; 419 } 420 421 public org.aspectj.weaver.tools.FuzzyBoolean matchesStatically(MatchingContext context) { 422 return this.contextMatch((Class)null); 423 } 424 425 public boolean mayNeedDynamicTest() { 426 return false; 427 } 428 429 private org.aspectj.weaver.tools.FuzzyBoolean contextMatch(@Nullable Class<?> targetType) { 430 String advisedBeanName = AspectJExpressionPointcut.this.getCurrentProxiedBeanName(); 431 if (advisedBeanName == null) { 432 return org.aspectj.weaver.tools.FuzzyBoolean.MAYBE; 433 } else if (BeanFactoryUtils.isGeneratedBeanName(advisedBeanName)) { 434 return org.aspectj.weaver.tools.FuzzyBoolean.NO; 435 } else if (targetType != null) { 436 boolean isFactory = FactoryBean.class.isAssignableFrom(targetType); 437 return org.aspectj.weaver.tools.FuzzyBoolean.fromBoolean(this.matchesBean(isFactory ? "&" + advisedBeanName : advisedBeanName)); 438 } else { 439 return org.aspectj.weaver.tools.FuzzyBoolean.fromBoolean(this.matchesBean(advisedBeanName) || this.matchesBean("&" + advisedBeanName)); 440 } 441 } 442 443 private boolean matchesBean(String advisedBeanName) { 444 return BeanFactoryAnnotationUtils.isQualifierMatch(this.expressionPattern::matches, advisedBeanName, AspectJExpressionPointcut.this.beanFactory); 445 } 446 } 447 448 private class BeanPointcutDesignatorHandler implements PointcutDesignatorHandler { 449 private static final String BEAN_DESIGNATOR_NAME = "bean"; 450 451 private BeanPointcutDesignatorHandler() { 452 } 453 454 public String getDesignatorName() { 455 return "bean"; 456 } 457 458 public ContextBasedMatcher parse(String expression) { 459 return AspectJExpressionPointcut.this.new BeanContextMatcher(expression); 460 } 461 } 462 }
那下面就挑一部分代码来看,首先看静态代码块,里面的Set放的是切面表达式所支持的类型
1 private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<>(); 2 3 static { 4 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION); 5 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS); 6 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE); 7 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS); 8 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET); 9 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN); 10 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION); 11 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN); 12 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS); 13 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET); 14 }
切点表达式类型:
- execution表达式:能在运行指定方法时拦截指定方法,用的最多。
- args:匹配参数,当执行的方法的参数是指定类型时生效。
- reference:表示引用其他命名切入点,只有@ApectJ风格支持,Schema风格不支持
- this:Spring Aop是基于代理的,生成的bean也是一个代理对象,this就是这个代理对象,当这个对象可以转换为指定的类型时,对应的切入点就是它了,Spring Aop将生效。
- target:当被代理的对象可以转换为指定的类型时,对应的切入点就是它了,Spring Aop将生效。
- within:指定某些类型的全部方法执行,也可用来指定一个包。
- @target:当代理的目标对象上拥有指定的注解时生效。
- @args:当执行的方法参数类型上拥有指定的注解时生效。
- @within:与@target类似,看官方文档和网上的说法都是@within只需要目标对象的类或者父类上有指定的注解,则@within会生效,而@target则是必须是目标对象的类上有指定的注解。而根据笔者的测试这两者都是只要目标类或父类上有指定的注解即可。
- @annotation:当执行的方法上拥有指定的注解时生效。
还有一种是Spring Aop扩展的类型 bean:当调用的方法是指定的bean的方法时生效。
AspectJExpressionPointcut 的属性里面还有 PointcutExpression,是org.aspectj.weaver.tools.PointcutExpression 中的类 ,经过一系列操作后由org.aspectj.weaver.tools.PointcutParser#parsePointcutExpression 从字符串表达式解析出来。
1 @Nullable 2 private transient PointcutExpression pointcutExpression;
这个是ClassFilter 接口的实现方法,借助的 PointcutExpression#couldMatchJoinPointsInType 去匹配,其参数为一个代表被检测类Class的实例,如果切入点适合该类,则返回true
1 @Override 2 public boolean matches(Class<?> targetClass) { 3 PointcutExpression pointcutExpression = obtainPointcutExpression(); 4 try { 5 try { 6 return pointcutExpression.couldMatchJoinPointsInType(targetClass); 7 } 8 catch (ReflectionWorldException ex) { 9 logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex); 10 // Actually this is still a "maybe" - treat the pointcut as dynamic if we don‘t know enough yet 11 PointcutExpression fallbackExpression = getFallbackPointcutExpression(targetClass); 12 if (fallbackExpression != null) { 13 return fallbackExpression.couldMatchJoinPointsInType(targetClass); 14 } 15 } 16 } 17 catch (Throwable ex) { 18 logger.debug("PointcutExpression matching rejected target class", ex); 19 } 20 return false; 21 }
下面这个是 MethodMatcher 接口中的 match 方法,作为Spring支持静态和动态的MethodMatcher。执行静态检查给定的方法是否匹配。
1 @Override 2 public boolean matches(Method method, Class<?> targetClass, Object... args) { 3 obtainPointcutExpression(); 4 ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass); 5 6 // Bind Spring AOP proxy to AspectJ "this" and Spring AOP target to AspectJ target, 7 // consistent with return of MethodInvocationProceedingJoinPoint 8 ProxyMethodInvocation pmi = null; 9 Object targetObject = null; 10 Object thisObject = null; 11 try { 12 MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation(); 13 targetObject = mi.getThis(); 14 if (!(mi instanceof ProxyMethodInvocation)) { 15 throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi); 16 } 17 pmi = (ProxyMethodInvocation) mi; 18 thisObject = pmi.getProxy(); 19 } 20 catch (IllegalStateException ex) { 21 // No current invocation... 22 if (logger.isDebugEnabled()) { 23 logger.debug("Could not access current invocation - matching with limited context: " + ex); 24 } 25 } 26 27 try { 28 JoinPointMatch joinPointMatch = shadowMatch.matchesJoinPoint(thisObject, targetObject, args); 29 30 /* 31 * Do a final check to see if any this(TYPE) kind of residue match. For 32 * this purpose, we use the original method‘s (proxy method‘s) shadow to 33 * ensure that ‘this‘ is correctly checked against. Without this check, 34 * we get incorrect match on this(TYPE) where TYPE matches the target 35 * type but not ‘this‘ (as would be the case of JDK dynamic proxies). 36 * <p>See SPR-2979 for the original bug. 37 */ 38 if (pmi != null && thisObject != null) { // there is a current invocation 39 RuntimeTestWalker originalMethodResidueTest = getRuntimeTestWalker(getShadowMatch(method, method)); 40 if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) { 41 return false; 42 } 43 if (joinPointMatch.matches()) { 44 bindParameters(pmi, joinPointMatch); 45 } 46 } 47 48 return joinPointMatch.matches(); 49 } 50 catch (Throwable ex) { 51 if (logger.isDebugEnabled()) { 52 logger.debug("Failed to evaluate join point for arguments " + Arrays.asList(args) + 53 " - falling back to non-match", ex); 54 } 55 return false; 56 } 57 }
初始化一个基础的AspectJ切入点解析器,BeanPointcutDesignatorHandler 这个是Spring实现真正解析的内部类。
1 /** 2 * Initialize the underlying AspectJ pointcut parser. 3 */ 4 private PointcutParser initializePointcutParser(@Nullable ClassLoader classLoader) { 5 PointcutParser parser = PointcutParser 6 .getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution( 7 SUPPORTED_PRIMITIVES, classLoader); 8 parser.registerPointcutDesignatorHandler(new BeanPointcutDesignatorHandler()); // 注册了一个BeanPointcutDesignatorHandler它是处理Spring自己支持的bean()的切点表达式的 9 return parser; 10 }
总结
原文地址:https://www.cnblogs.com/magic-sea/p/11735470.html