AOP源码解析:AspectJExpressionPointcutAdvisor类
先看看 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 }
总结
AOP源码解析:AspectJExpressionPointcutAdvisor类的更多相关文章
- AOP源码解析:AspectJAwareAdvisorAutoProxyCreator类的介绍
AspectJAwareAdvisorAutoProxyCreator 的类图 上图中一些 类/接口 的介绍: AspectJAwareAdvisorAutoProxyCreator : 公开了Asp ...
- AOP源码解析之二-创建AOP代理前传,获取AOP信息
AOP源码解析之二-创建AOP代理前传,获取AOP信息. 上篇文章对AOP的基本概念说清楚了,那么接下来的AOP还剩下两个大的步骤获取定义的AOP信息,生成代理对象扔到beanFactory中. 本篇 ...
- 老生常谈系列之Aop--Spring Aop源码解析(二)
老生常谈系列之Aop--Spring Aop源码解析(二) 前言 上一篇文章老生常谈系列之Aop--Spring Aop源码解析(一)已经介绍完Spring Aop获取advice切面增强方法的逻辑, ...
- 老生常谈系列之Aop--Spring Aop源码解析(一)
老生常谈系列之Aop--Spring Aop源码解析(一) 前言 上一篇文章老生常谈系列之Aop--Spring Aop原理浅析大概阐述了动态代理的相关知识,并且最后的图给了一个Spring Aop实 ...
- 【Spring源码分析】AOP源码解析(上篇)
前言 前面写了六篇文章详细地分析了Spring Bean加载流程,这部分完了之后就要进入一个比较困难的部分了,就是AOP的实现原理分析.为了探究AOP实现原理,首先定义几个类,一个Dao接口: pub ...
- 第四章 dubbo内核之aop源码解析
ExtensionLoader<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class); final P ...
- Spring系列(五):Spring AOP源码解析
一.@EnableAspectJAutoProxy注解 在主配置类中添加@EnableAspectJAutoProxy注解,开启aop支持,那么@EnableAspectJAutoProxy到底做了什 ...
- [Java源码解析] -- String类的compareTo(String otherString)方法的源码解析
String类下的compareTo(String otherString)方法的源码解析 一. 前言 近日研究了一下String类的一些方法, 通过查看源码, 对一些常用的方法也有了更透彻的认识, ...
- spring源码系列8:AOP源码解析之代理的创建
回顾 首先回顾: JDK动态代理与CGLIB动态代理 Spring中的InstantiationAwareBeanPostProcessor和BeanPostProcessor的区别 我们得知 JDK ...
随机推荐
- eclipes常见操作总结及项目2和3经验总结
eclipes常见操作总结及项目2经验总结 eclipes提示: 打开eclipes 选择window->perference->java->editor->content a ...
- Oracle列值拼接
最近在学习的过程中,发现一个挺有意思的函数,它可实现对列值的拼接.下面我们来看看其具体用法. 用法: 对其作用,官方文档的解释如下: For a specified measure, LISTAGG ...
- 学习PHP中的信息格式化操作
在国际化组件的学习过程中,我们已经接触过了 NumberFormatter 这种数字的格式化操作,它可以让我们将数字转换成标准格式.货币.本地语言等形式.今天我们来学习的是另一种专门用于信息格式化的类 ...
- Java基础系列(1)- JDK、JRE、JVM
Java三大版本(Write Once:Run Anywhere) JavaSE:标准版 JavaME:嵌入式开发 JavaEE:E企业级开发 JDK.JRE.JVM JDK是开发工具包 JRE是编译 ...
- OC源码剖析对象的本质
1. 类的底层实现 先写一个 Person 类: @interface Person : NSObject @property (nonatomic, copy) NSString *p_name; ...
- Ubuntu怎么开启/关闭防火墙
在Ubuntu中,使用sudo ufw status命令查看当前防火墙状态. 不活动,是关闭状态. 在Ubuntu中,使用sudo ufw enable命令来开启防火墙. 在Ubuntu中,使用sud ...
- pyqt5无边框拖动
from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * import sys class ...
- requests + 正则表达式 获取 ‘猫眼电影top100’。
使用 进程池Pool 提高爬取数据的速度. 1 # !/usr/bin/python 2 # -*- coding:utf-8 -*- 3 import requests 4 from request ...
- 博客调网易云歌单JS
<!--音乐--> <link rel="stylesheet" href="https://blog-static.cnblogs.com/files ...
- redis无法连接
Exception in thread "main" redis.clients.jedis.exceptions.JedisDataException: DENIED Redi ...