先看看 AspectJExpressionPointcutAdvisor 的类图

  再了解一下切点(Pointcut)表达式,它指定触发advice的方法,可以精确到返回参数,参数类型,方法名

  1. 1 package concert;
  2. 2
  3. 3 public interface Performance {
  4. 4 void perform();
  5. 5 }

  AspectJExpressionPointcutAdvisor 源码,官方文档解释说这是可以用于任何AspectJ切入点表达式的 Spring AOP Advisor。

  1. 1 @SuppressWarnings("serial")
  2. 2 public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdvisor implements BeanFactoryAware {
  3. 3
  4. 4 private final AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); // AspectJ表达式切点匹配器
  5. 5
  6. 6
  7. 7 public void setExpression(@Nullable String expression) {
  8. 8 this.pointcut.setExpression(expression);
  9. 9 }
  10. 10
  11. 11 @Nullable
  12. 12 public String getExpression() {
  13. 13 return this.pointcut.getExpression();
  14. 14 }
  15. 15
  16. 16 public void setLocation(@Nullable String location) {
  17. 17 this.pointcut.setLocation(location);
  18. 18 }
  19. 19
  20. 20 @Nullable
  21. 21 public String getLocation() {
  22. 22 return this.pointcut.getLocation();
  23. 23 }
  24. 24
  25. 25 public void setParameterNames(String... names) {
  26. 26 this.pointcut.setParameterNames(names);
  27. 27 }
  28. 28
  29. 29 public void setParameterTypes(Class<?>... types) {
  30. 30 this.pointcut.setParameterTypes(types);
  31. 31 }
  32. 32
  33. 33 @Override
  34. 34 public void setBeanFactory(BeanFactory beanFactory) {
  35. 35 this.pointcut.setBeanFactory(beanFactory);
  36. 36 }
  37. 37
  38. 38 @Override
  39. 39 public Pointcut getPointcut() {
  40. 40 return this.pointcut;
  41. 41 }
  42. 42
  43. 43 }

  再看看 AspectJExpressionPointcutAdvisor 的抽象父类 AbstractGenericPointcutAdvisor 的源码

  1. 1 @SuppressWarnings("serial")
  2. 2 public abstract class AbstractGenericPointcutAdvisor extends AbstractPointcutAdvisor {
  3. 3
  4. 4 private Advice advice = EMPTY_ADVICE; // Advisor接口中定义的占位符
  5. 5
  6. 6
  7. 7 /**
  8. 8 * Specify the advice that this advisor should apply.
  9. 9 */
  10. 10 public void setAdvice(Advice advice) {
  11. 11 this.advice = advice;
  12. 12 }
  13. 13
  14. 14 @Override
  15. 15 public Advice getAdvice() {
  16. 16 return this.advice;
  17. 17 }
  18. 18
  19. 19
  20. 20 @Override
  21. 21 public String toString() {
  22. 22 return getClass().getName() + ": advice [" + getAdvice() + "]";
  23. 23 }
  24. 24
  25. 25 }

  看完源码后,可以了解到一个 AspectJExpressionPointcutAdvisor 是用来处理对应 AspectJ 的 advice 和切点的,可以在代码中看见有advice的设置和获取、切点表达式的一些处理、设置切点的Bean工厂,还有获取该切点。该 AspectJExpressionPointcutAdvisor 创建了一个 AspectJExpressionPointcut,它们之间的关系是一对一的组合关系,如同字面意思,AspectJExpressionPointcut 与切点表达式有关。

  下面是 AspectJExpressionPointcut 的类图

  AspectJExpressionPointcut 的源码(过长折叠起来了)

  1. 1 public class AspectJExpressionPointcut extends AbstractExpressionPointcut implements ClassFilter, IntroductionAwareMethodMatcher, BeanFactoryAware {
  2. 2 private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet();
  3. 3 private static final Log logger;
  4. 4 @Nullable
  5. 5 private Class<?> pointcutDeclarationScope;
  6. 6 private String[] pointcutParameterNames = new String[0];
  7. 7 private Class<?>[] pointcutParameterTypes = new Class[0];
  8. 8 @Nullable
  9. 9 private BeanFactory beanFactory;
  10. 10 @Nullable
  11. 11 private transient ClassLoader pointcutClassLoader;
  12. 12 @Nullable
  13. 13 private transient PointcutExpression pointcutExpression;
  14. 14 private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap(32);
  15. 15
  16. 16 public AspectJExpressionPointcut() {
  17. 17 }
  18. 18
  19. 19 public AspectJExpressionPointcut(Class<?> declarationScope, String[] paramNames, Class<?>[] paramTypes) {
  20. 20 this.pointcutDeclarationScope = declarationScope;
  21. 21 if (paramNames.length != paramTypes.length) {
  22. 22 throw new IllegalStateException("Number of pointcut parameter names must match number of pointcut parameter types");
  23. 23 } else {
  24. 24 this.pointcutParameterNames = paramNames;
  25. 25 this.pointcutParameterTypes = paramTypes;
  26. 26 }
  27. 27 }
  28. 28
  29. 29 public void setPointcutDeclarationScope(Class<?> pointcutDeclarationScope) {
  30. 30 this.pointcutDeclarationScope = pointcutDeclarationScope;
  31. 31 }
  32. 32
  33. 33 public void setParameterNames(String... names) {
  34. 34 this.pointcutParameterNames = names;
  35. 35 }
  36. 36
  37. 37 public void setParameterTypes(Class<?>... types) {
  38. 38 this.pointcutParameterTypes = types;
  39. 39 }
  40. 40
  41. 41 public void setBeanFactory(BeanFactory beanFactory) {
  42. 42 this.beanFactory = beanFactory;
  43. 43 }
  44. 44
  45. 45 public ClassFilter getClassFilter() {
  46. 46 this.obtainPointcutExpression();
  47. 47 return this;
  48. 48 }
  49. 49
  50. 50 public MethodMatcher getMethodMatcher() {
  51. 51 this.obtainPointcutExpression();
  52. 52 return this;
  53. 53 }
  54. 54
  55. 55 private PointcutExpression obtainPointcutExpression() {
  56. 56 if (this.getExpression() == null) {
  57. 57 throw new IllegalStateException("Must set property 'expression' before attempting to match");
  58. 58 } else {
  59. 59 if (this.pointcutExpression == null) {
  60. 60 this.pointcutClassLoader = this.determinePointcutClassLoader();
  61. 61 this.pointcutExpression = this.buildPointcutExpression(this.pointcutClassLoader);
  62. 62 }
  63. 63
  64. 64 return this.pointcutExpression;
  65. 65 }
  66. 66 }
  67. 67
  68. 68 @Nullable
  69. 69 private ClassLoader determinePointcutClassLoader() {
  70. 70 if (this.beanFactory instanceof ConfigurableBeanFactory) {
  71. 71 return ((ConfigurableBeanFactory)this.beanFactory).getBeanClassLoader();
  72. 72 } else {
  73. 73 return this.pointcutDeclarationScope != null ? this.pointcutDeclarationScope.getClassLoader() : ClassUtils.getDefaultClassLoader();
  74. 74 }
  75. 75 }
  76. 76
  77. 77 private PointcutExpression buildPointcutExpression(@Nullable ClassLoader classLoader) {
  78. 78 PointcutParser parser = this.initializePointcutParser(classLoader);
  79. 79 PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
  80. 80
  81. 81 for(int i = 0; i < pointcutParameters.length; ++i) {
  82. 82 pointcutParameters[i] = parser.createPointcutParameter(this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
  83. 83 }
  84. 84
  85. 85 return parser.parsePointcutExpression(this.replaceBooleanOperators(this.resolveExpression()), this.pointcutDeclarationScope, pointcutParameters);
  86. 86 }
  87. 87
  88. 88 private String resolveExpression() {
  89. 89 String expression = this.getExpression();
  90. 90 Assert.state(expression != null, "No expression set");
  91. 91 return expression;
  92. 92 }
  93. 93
  94. 94 private PointcutParser initializePointcutParser(@Nullable ClassLoader classLoader) {
  95. 95 PointcutParser parser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, classLoader);
  96. 96 parser.registerPointcutDesignatorHandler(new AspectJExpressionPointcut.BeanPointcutDesignatorHandler());
  97. 97 return parser;
  98. 98 }
  99. 99
  100. 100 private String replaceBooleanOperators(String pcExpr) {
  101. 101 String result = StringUtils.replace(pcExpr, " and ", " && ");
  102. 102 result = StringUtils.replace(result, " or ", " || ");
  103. 103 result = StringUtils.replace(result, " not ", " ! ");
  104. 104 return result;
  105. 105 }
  106. 106
  107. 107 public PointcutExpression getPointcutExpression() {
  108. 108 return this.obtainPointcutExpression();
  109. 109 }
  110. 110
  111. 111 public boolean matches(Class<?> targetClass) {
  112. 112 PointcutExpression pointcutExpression = this.obtainPointcutExpression();
  113. 113
  114. 114 try {
  115. 115 try {
  116. 116 return pointcutExpression.couldMatchJoinPointsInType(targetClass);
  117. 117 } catch (ReflectionWorldException var5) {
  118. 118 logger.debug("PointcutExpression matching rejected target class - trying fallback expression", var5);
  119. 119 PointcutExpression fallbackExpression = this.getFallbackPointcutExpression(targetClass);
  120. 120 if (fallbackExpression != null) {
  121. 121 return fallbackExpression.couldMatchJoinPointsInType(targetClass);
  122. 122 }
  123. 123 }
  124. 124 } catch (Throwable var6) {
  125. 125 logger.debug("PointcutExpression matching rejected target class", var6);
  126. 126 }
  127. 127
  128. 128 return false;
  129. 129 }
  130. 130
  131. 131 public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
  132. 132 this.obtainPointcutExpression();
  133. 133 ShadowMatch shadowMatch = this.getTargetShadowMatch(method, targetClass);
  134. 134 if (shadowMatch.alwaysMatches()) {
  135. 135 return true;
  136. 136 } else if (shadowMatch.neverMatches()) {
  137. 137 return false;
  138. 138 } else if (hasIntroductions) {
  139. 139 return true;
  140. 140 } else {
  141. 141 RuntimeTestWalker walker = this.getRuntimeTestWalker(shadowMatch);
  142. 142 return !walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass);
  143. 143 }
  144. 144 }
  145. 145
  146. 146 public boolean matches(Method method, Class<?> targetClass) {
  147. 147 return this.matches(method, targetClass, false);
  148. 148 }
  149. 149
  150. 150 public boolean isRuntime() {
  151. 151 return this.obtainPointcutExpression().mayNeedDynamicTest();
  152. 152 }
  153. 153
  154. 154 public boolean matches(Method method, Class<?> targetClass, Object... args) {
  155. 155 this.obtainPointcutExpression();
  156. 156 ShadowMatch shadowMatch = this.getTargetShadowMatch(method, targetClass);
  157. 157 ProxyMethodInvocation pmi = null;
  158. 158 Object targetObject = null;
  159. 159 Object thisObject = null;
  160. 160
  161. 161 try {
  162. 162 MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
  163. 163 targetObject = mi.getThis();
  164. 164 if (!(mi instanceof ProxyMethodInvocation)) {
  165. 165 throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
  166. 166 }
  167. 167
  168. 168 pmi = (ProxyMethodInvocation)mi;
  169. 169 thisObject = pmi.getProxy();
  170. 170 } catch (IllegalStateException var11) {
  171. 171 if (logger.isDebugEnabled()) {
  172. 172 logger.debug("Could not access current invocation - matching with limited context: " + var11);
  173. 173 }
  174. 174 }
  175. 175
  176. 176 try {
  177. 177 JoinPointMatch joinPointMatch = shadowMatch.matchesJoinPoint(thisObject, targetObject, args);
  178. 178 if (pmi != null && thisObject != null) {
  179. 179 RuntimeTestWalker originalMethodResidueTest = this.getRuntimeTestWalker(this.getShadowMatch(method, method));
  180. 180 if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
  181. 181 return false;
  182. 182 }
  183. 183
  184. 184 if (joinPointMatch.matches()) {
  185. 185 this.bindParameters(pmi, joinPointMatch);
  186. 186 }
  187. 187 }
  188. 188
  189. 189 return joinPointMatch.matches();
  190. 190 } catch (Throwable var10) {
  191. 191 if (logger.isDebugEnabled()) {
  192. 192 logger.debug("Failed to evaluate join point for arguments " + Arrays.asList(args) + " - falling back to non-match", var10);
  193. 193 }
  194. 194
  195. 195 return false;
  196. 196 }
  197. 197 }
  198. 198
  199. 199 @Nullable
  200. 200 protected String getCurrentProxiedBeanName() {
  201. 201 return ProxyCreationContext.getCurrentProxiedBeanName();
  202. 202 }
  203. 203
  204. 204 @Nullable
  205. 205 private PointcutExpression getFallbackPointcutExpression(Class<?> targetClass) {
  206. 206 try {
  207. 207 ClassLoader classLoader = targetClass.getClassLoader();
  208. 208 if (classLoader != null && classLoader != this.pointcutClassLoader) {
  209. 209 return this.buildPointcutExpression(classLoader);
  210. 210 }
  211. 211 } catch (Throwable var3) {
  212. 212 logger.debug("Failed to create fallback PointcutExpression", var3);
  213. 213 }
  214. 214
  215. 215 return null;
  216. 216 }
  217. 217
  218. 218 private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) {
  219. 219 return shadowMatch instanceof AspectJExpressionPointcut.DefensiveShadowMatch ? new RuntimeTestWalker(((AspectJExpressionPointcut.DefensiveShadowMatch)shadowMatch).primary) : new RuntimeTestWalker(shadowMatch);
  220. 220 }
  221. 221
  222. 222 private void bindParameters(ProxyMethodInvocation invocation, JoinPointMatch jpm) {
  223. 223 invocation.setUserAttribute(this.resolveExpression(), jpm);
  224. 224 }
  225. 225
  226. 226 private ShadowMatch getTargetShadowMatch(Method method, Class<?> targetClass) {
  227. 227 Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
  228. 228 if (targetMethod.getDeclaringClass().isInterface()) {
  229. 229 Set<Class<?>> ifcs = ClassUtils.getAllInterfacesForClassAsSet(targetClass);
  230. 230 if (ifcs.size() > 1) {
  231. 231 try {
  232. 232 Class<?> compositeInterface = ClassUtils.createCompositeInterface(ClassUtils.toClassArray(ifcs), targetClass.getClassLoader());
  233. 233 targetMethod = ClassUtils.getMostSpecificMethod(targetMethod, compositeInterface);
  234. 234 } catch (IllegalArgumentException var6) {
  235. 235 }
  236. 236 }
  237. 237 }
  238. 238
  239. 239 return this.getShadowMatch(targetMethod, method);
  240. 240 }
  241. 241
  242. 242 private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) {
  243. 243 ShadowMatch shadowMatch = (ShadowMatch)this.shadowMatchCache.get(targetMethod);
  244. 244 if (shadowMatch == null) {
  245. 245 synchronized(this.shadowMatchCache) {
  246. 246 PointcutExpression fallbackExpression = null;
  247. 247 shadowMatch = (ShadowMatch)this.shadowMatchCache.get(targetMethod);
  248. 248 if (shadowMatch == null) {
  249. 249 Method methodToMatch = targetMethod;
  250. 250
  251. 251 try {
  252. 252 try {
  253. 253 shadowMatch = this.obtainPointcutExpression().matchesMethodExecution(methodToMatch);
  254. 254 } catch (ReflectionWorldException var13) {
  255. 255 try {
  256. 256 fallbackExpression = this.getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
  257. 257 if (fallbackExpression != null) {
  258. 258 shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
  259. 259 }
  260. 260 } catch (ReflectionWorldException var12) {
  261. 261 fallbackExpression = null;
  262. 262 }
  263. 263 }
  264. 264
  265. 265 if (targetMethod != originalMethod && (shadowMatch == null || ((ShadowMatch)shadowMatch).neverMatches() && Proxy.isProxyClass(targetMethod.getDeclaringClass()))) {
  266. 266 methodToMatch = originalMethod;
  267. 267
  268. 268 try {
  269. 269 shadowMatch = this.obtainPointcutExpression().matchesMethodExecution(methodToMatch);
  270. 270 } catch (ReflectionWorldException var11) {
  271. 271 try {
  272. 272 fallbackExpression = this.getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
  273. 273 if (fallbackExpression != null) {
  274. 274 shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
  275. 275 }
  276. 276 } catch (ReflectionWorldException var10) {
  277. 277 fallbackExpression = null;
  278. 278 }
  279. 279 }
  280. 280 }
  281. 281 } catch (Throwable var14) {
  282. 282 logger.debug("PointcutExpression matching rejected target method", var14);
  283. 283 fallbackExpression = null;
  284. 284 }
  285. 285
  286. 286 if (shadowMatch == null) {
  287. 287 shadowMatch = new ShadowMatchImpl(FuzzyBoolean.NO, (Test)null, (ExposedState)null, (PointcutParameter[])null);
  288. 288 } else if (((ShadowMatch)shadowMatch).maybeMatches() && fallbackExpression != null) {
  289. 289 shadowMatch = new AspectJExpressionPointcut.DefensiveShadowMatch((ShadowMatch)shadowMatch, fallbackExpression.matchesMethodExecution(methodToMatch));
  290. 290 }
  291. 291
  292. 292 this.shadowMatchCache.put(targetMethod, shadowMatch);
  293. 293 }
  294. 294 }
  295. 295 }
  296. 296
  297. 297 return (ShadowMatch)shadowMatch;
  298. 298 }
  299. 299
  300. 300 public boolean equals(Object other) {
  301. 301 if (this == other) {
  302. 302 return true;
  303. 303 } else if (!(other instanceof AspectJExpressionPointcut)) {
  304. 304 return false;
  305. 305 } else {
  306. 306 AspectJExpressionPointcut otherPc = (AspectJExpressionPointcut)other;
  307. 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. 308 }
  309. 309 }
  310. 310
  311. 311 public int hashCode() {
  312. 312 int hashCode = ObjectUtils.nullSafeHashCode(this.getExpression());
  313. 313 hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutDeclarationScope);
  314. 314 hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutParameterNames);
  315. 315 hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutParameterTypes);
  316. 316 return hashCode;
  317. 317 }
  318. 318
  319. 319 public String toString() {
  320. 320 StringBuilder sb = new StringBuilder();
  321. 321 sb.append("AspectJExpressionPointcut: ");
  322. 322 sb.append("(");
  323. 323
  324. 324 for(int i = 0; i < this.pointcutParameterTypes.length; ++i) {
  325. 325 sb.append(this.pointcutParameterTypes[i].getName());
  326. 326 sb.append(" ");
  327. 327 sb.append(this.pointcutParameterNames[i]);
  328. 328 if (i + 1 < this.pointcutParameterTypes.length) {
  329. 329 sb.append(", ");
  330. 330 }
  331. 331 }
  332. 332
  333. 333 sb.append(")");
  334. 334 sb.append(" ");
  335. 335 if (this.getExpression() != null) {
  336. 336 sb.append(this.getExpression());
  337. 337 } else {
  338. 338 sb.append("<pointcut expression not set>");
  339. 339 }
  340. 340
  341. 341 return sb.toString();
  342. 342 }
  343. 343
  344. 344 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
  345. 345 ois.defaultReadObject();
  346. 346 this.shadowMatchCache = new ConcurrentHashMap(32);
  347. 347 }
  348. 348
  349. 349 static {
  350. 350 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
  351. 351 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS);
  352. 352 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE);
  353. 353 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS);
  354. 354 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET);
  355. 355 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN);
  356. 356 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION);
  357. 357 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN);
  358. 358 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS);
  359. 359 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET);
  360. 360 logger = LogFactory.getLog(AspectJExpressionPointcut.class);
  361. 361 }
  362. 362
  363. 363 private static class DefensiveShadowMatch implements ShadowMatch {
  364. 364 private final ShadowMatch primary;
  365. 365 private final ShadowMatch other;
  366. 366
  367. 367 public DefensiveShadowMatch(ShadowMatch primary, ShadowMatch other) {
  368. 368 this.primary = primary;
  369. 369 this.other = other;
  370. 370 }
  371. 371
  372. 372 public boolean alwaysMatches() {
  373. 373 return this.primary.alwaysMatches();
  374. 374 }
  375. 375
  376. 376 public boolean maybeMatches() {
  377. 377 return this.primary.maybeMatches();
  378. 378 }
  379. 379
  380. 380 public boolean neverMatches() {
  381. 381 return this.primary.neverMatches();
  382. 382 }
  383. 383
  384. 384 public JoinPointMatch matchesJoinPoint(Object thisObject, Object targetObject, Object[] args) {
  385. 385 try {
  386. 386 return this.primary.matchesJoinPoint(thisObject, targetObject, args);
  387. 387 } catch (ReflectionWorldException var5) {
  388. 388 return this.other.matchesJoinPoint(thisObject, targetObject, args);
  389. 389 }
  390. 390 }
  391. 391
  392. 392 public void setMatchingContext(MatchingContext aMatchContext) {
  393. 393 this.primary.setMatchingContext(aMatchContext);
  394. 394 this.other.setMatchingContext(aMatchContext);
  395. 395 }
  396. 396 }
  397. 397
  398. 398 private class BeanContextMatcher implements ContextBasedMatcher {
  399. 399 private final NamePattern expressionPattern;
  400. 400
  401. 401 public BeanContextMatcher(String expression) {
  402. 402 this.expressionPattern = new NamePattern(expression);
  403. 403 }
  404. 404
  405. 405 /** @deprecated */
  406. 406 @Deprecated
  407. 407 public boolean couldMatchJoinPointsInType(Class someClass) {
  408. 408 return this.contextMatch(someClass) == org.aspectj.weaver.tools.FuzzyBoolean.YES;
  409. 409 }
  410. 410
  411. 411 /** @deprecated */
  412. 412 @Deprecated
  413. 413 public boolean couldMatchJoinPointsInType(Class someClass, MatchingContext context) {
  414. 414 return this.contextMatch(someClass) == org.aspectj.weaver.tools.FuzzyBoolean.YES;
  415. 415 }
  416. 416
  417. 417 public boolean matchesDynamically(MatchingContext context) {
  418. 418 return true;
  419. 419 }
  420. 420
  421. 421 public org.aspectj.weaver.tools.FuzzyBoolean matchesStatically(MatchingContext context) {
  422. 422 return this.contextMatch((Class)null);
  423. 423 }
  424. 424
  425. 425 public boolean mayNeedDynamicTest() {
  426. 426 return false;
  427. 427 }
  428. 428
  429. 429 private org.aspectj.weaver.tools.FuzzyBoolean contextMatch(@Nullable Class<?> targetType) {
  430. 430 String advisedBeanName = AspectJExpressionPointcut.this.getCurrentProxiedBeanName();
  431. 431 if (advisedBeanName == null) {
  432. 432 return org.aspectj.weaver.tools.FuzzyBoolean.MAYBE;
  433. 433 } else if (BeanFactoryUtils.isGeneratedBeanName(advisedBeanName)) {
  434. 434 return org.aspectj.weaver.tools.FuzzyBoolean.NO;
  435. 435 } else if (targetType != null) {
  436. 436 boolean isFactory = FactoryBean.class.isAssignableFrom(targetType);
  437. 437 return org.aspectj.weaver.tools.FuzzyBoolean.fromBoolean(this.matchesBean(isFactory ? "&" + advisedBeanName : advisedBeanName));
  438. 438 } else {
  439. 439 return org.aspectj.weaver.tools.FuzzyBoolean.fromBoolean(this.matchesBean(advisedBeanName) || this.matchesBean("&" + advisedBeanName));
  440. 440 }
  441. 441 }
  442. 442
  443. 443 private boolean matchesBean(String advisedBeanName) {
  444. 444 return BeanFactoryAnnotationUtils.isQualifierMatch(this.expressionPattern::matches, advisedBeanName, AspectJExpressionPointcut.this.beanFactory);
  445. 445 }
  446. 446 }
  447. 447
  448. 448 private class BeanPointcutDesignatorHandler implements PointcutDesignatorHandler {
  449. 449 private static final String BEAN_DESIGNATOR_NAME = "bean";
  450. 450
  451. 451 private BeanPointcutDesignatorHandler() {
  452. 452 }
  453. 453
  454. 454 public String getDesignatorName() {
  455. 455 return "bean";
  456. 456 }
  457. 457
  458. 458 public ContextBasedMatcher parse(String expression) {
  459. 459 return AspectJExpressionPointcut.this.new BeanContextMatcher(expression);
  460. 460 }
  461. 461 }
  462. 462 }

  那下面就挑一部分代码来看,首先看静态代码块,里面的Set放的是切面表达式所支持的类型

  1. 1 private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<>();
  2. 2
  3. 3 static {
  4. 4 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
  5. 5 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS);
  6. 6 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE);
  7. 7 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS);
  8. 8 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET);
  9. 9 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN);
  10. 10 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION);
  11. 11 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN);
  12. 12 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS);
  13. 13 SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET);
  14. 14 }

  切点表达式类型:

  1. execution表达式:能在运行指定方法时拦截指定方法,用的最多。

  2. args:匹配参数,当执行的方法的参数是指定类型时生效。

  3. reference:表示引用其他命名切入点,只有@ApectJ风格支持,Schema风格不支持

  4. this:Spring Aop是基于代理的,生成的bean也是一个代理对象,this就是这个代理对象,当这个对象可以转换为指定的类型时,对应的切入点就是它了,Spring Aop将生效。

  5. target:当被代理的对象可以转换为指定的类型时,对应的切入点就是它了,Spring Aop将生效。

  6. within:指定某些类型的全部方法执行,也可用来指定一个包。

  7. @target:当代理的目标对象上拥有指定的注解时生效。

  8. @args:当执行的方法参数类型上拥有指定的注解时生效。

  9. @within:与@target类似,看官方文档和网上的说法都是@within只需要目标对象的类或者父类上有指定的注解,则@within会生效,而@target则是必须是目标对象的类上有指定的注解。而根据笔者的测试这两者都是只要目标类或父类上有指定的注解即可。

  10. @annotation:当执行的方法上拥有指定的注解时生效。

  还有一种是Spring Aop扩展的类型 bean:当调用的方法是指定的bean的方法时生效。

  AspectJExpressionPointcut 的属性里面还有 PointcutExpression,是org.aspectj.weaver.tools.PointcutExpression 中的类 ,经过一系列操作后由org.aspectj.weaver.tools.PointcutParser#parsePointcutExpression 从字符串表达式解析出来。

  1. 1 @Nullable
  2. 2 private transient PointcutExpression pointcutExpression;

  这个是ClassFilter 接口的实现方法,借助的 PointcutExpression#couldMatchJoinPointsInType 去匹配,其参数为一个代表被检测类Class的实例,如果切入点适合该类,则返回true

  1. 1 @Override
  2. 2 public boolean matches(Class<?> targetClass) {
  3. 3 PointcutExpression pointcutExpression = obtainPointcutExpression();
  4. 4 try {
  5. 5 try {
  6. 6 return pointcutExpression.couldMatchJoinPointsInType(targetClass);
  7. 7 }
  8. 8 catch (ReflectionWorldException ex) {
  9. 9 logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex);
  10. 10 // Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
  11. 11 PointcutExpression fallbackExpression = getFallbackPointcutExpression(targetClass);
  12. 12 if (fallbackExpression != null) {
  13. 13 return fallbackExpression.couldMatchJoinPointsInType(targetClass);
  14. 14 }
  15. 15 }
  16. 16 }
  17. 17 catch (Throwable ex) {
  18. 18 logger.debug("PointcutExpression matching rejected target class", ex);
  19. 19 }
  20. 20 return false;
  21. 21 }

  下面这个是 MethodMatcher 接口中的 match 方法,作为Spring支持静态和动态的MethodMatcher。执行静态检查给定的方法是否匹配。

  1. 1   @Override
  2. 2 public boolean matches(Method method, Class<?> targetClass, Object... args) {
  3. 3 obtainPointcutExpression();
  4. 4 ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
  5. 5
  6. 6 // Bind Spring AOP proxy to AspectJ "this" and Spring AOP target to AspectJ target,
  7. 7 // consistent with return of MethodInvocationProceedingJoinPoint
  8. 8 ProxyMethodInvocation pmi = null;
  9. 9 Object targetObject = null;
  10. 10 Object thisObject = null;
  11. 11 try {
  12. 12 MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
  13. 13 targetObject = mi.getThis();
  14. 14 if (!(mi instanceof ProxyMethodInvocation)) {
  15. 15 throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
  16. 16 }
  17. 17 pmi = (ProxyMethodInvocation) mi;
  18. 18 thisObject = pmi.getProxy();
  19. 19 }
  20. 20 catch (IllegalStateException ex) {
  21. 21 // No current invocation...
  22. 22 if (logger.isDebugEnabled()) {
  23. 23 logger.debug("Could not access current invocation - matching with limited context: " + ex);
  24. 24 }
  25. 25 }
  26. 26
  27. 27 try {
  28. 28 JoinPointMatch joinPointMatch = shadowMatch.matchesJoinPoint(thisObject, targetObject, args);
  29. 29
  30. 30 /*
  31. 31 * Do a final check to see if any this(TYPE) kind of residue match. For
  32. 32 * this purpose, we use the original method's (proxy method's) shadow to
  33. 33 * ensure that 'this' is correctly checked against. Without this check,
  34. 34 * we get incorrect match on this(TYPE) where TYPE matches the target
  35. 35 * type but not 'this' (as would be the case of JDK dynamic proxies).
  36. 36 * <p>See SPR-2979 for the original bug.
  37. 37 */
  38. 38 if (pmi != null && thisObject != null) { // there is a current invocation
  39. 39 RuntimeTestWalker originalMethodResidueTest = getRuntimeTestWalker(getShadowMatch(method, method));
  40. 40 if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
  41. 41 return false;
  42. 42 }
  43. 43 if (joinPointMatch.matches()) {
  44. 44 bindParameters(pmi, joinPointMatch);
  45. 45 }
  46. 46 }
  47. 47
  48. 48 return joinPointMatch.matches();
  49. 49 }
  50. 50 catch (Throwable ex) {
  51. 51 if (logger.isDebugEnabled()) {
  52. 52 logger.debug("Failed to evaluate join point for arguments " + Arrays.asList(args) +
  53. 53 " - falling back to non-match", ex);
  54. 54 }
  55. 55 return false;
  56. 56 }
  57. 57 }

  初始化一个基础的AspectJ切入点解析器,BeanPointcutDesignatorHandler 这个是Spring实现真正解析的内部类。

  1. 1 /**
  2. 2 * Initialize the underlying AspectJ pointcut parser.
  3. 3 */
  4. 4 private PointcutParser initializePointcutParser(@Nullable ClassLoader classLoader) {
  5. 5 PointcutParser parser = PointcutParser
  6. 6 .getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(
  7. 7 SUPPORTED_PRIMITIVES, classLoader);
  8. 8 parser.registerPointcutDesignatorHandler(new BeanPointcutDesignatorHandler()); // 注册了一个BeanPointcutDesignatorHandler它是处理Spring自己支持的bean()的切点表达式的
  9. 9 return parser;
  10. 10 }

总结

AOP源码解析:AspectJExpressionPointcutAdvisor类的更多相关文章

  1. AOP源码解析:AspectJAwareAdvisorAutoProxyCreator类的介绍

    AspectJAwareAdvisorAutoProxyCreator 的类图 上图中一些 类/接口 的介绍: AspectJAwareAdvisorAutoProxyCreator : 公开了Asp ...

  2. AOP源码解析之二-创建AOP代理前传,获取AOP信息

    AOP源码解析之二-创建AOP代理前传,获取AOP信息. 上篇文章对AOP的基本概念说清楚了,那么接下来的AOP还剩下两个大的步骤获取定义的AOP信息,生成代理对象扔到beanFactory中. 本篇 ...

  3. 老生常谈系列之Aop--Spring Aop源码解析(二)

    老生常谈系列之Aop--Spring Aop源码解析(二) 前言 上一篇文章老生常谈系列之Aop--Spring Aop源码解析(一)已经介绍完Spring Aop获取advice切面增强方法的逻辑, ...

  4. 老生常谈系列之Aop--Spring Aop源码解析(一)

    老生常谈系列之Aop--Spring Aop源码解析(一) 前言 上一篇文章老生常谈系列之Aop--Spring Aop原理浅析大概阐述了动态代理的相关知识,并且最后的图给了一个Spring Aop实 ...

  5. 【Spring源码分析】AOP源码解析(上篇)

    前言 前面写了六篇文章详细地分析了Spring Bean加载流程,这部分完了之后就要进入一个比较困难的部分了,就是AOP的实现原理分析.为了探究AOP实现原理,首先定义几个类,一个Dao接口: pub ...

  6. 第四章 dubbo内核之aop源码解析

    ExtensionLoader<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class); final P ...

  7. Spring系列(五):Spring AOP源码解析

    一.@EnableAspectJAutoProxy注解 在主配置类中添加@EnableAspectJAutoProxy注解,开启aop支持,那么@EnableAspectJAutoProxy到底做了什 ...

  8. [Java源码解析] -- String类的compareTo(String otherString)方法的源码解析

    String类下的compareTo(String otherString)方法的源码解析 一. 前言 近日研究了一下String类的一些方法, 通过查看源码, 对一些常用的方法也有了更透彻的认识,  ...

  9. spring源码系列8:AOP源码解析之代理的创建

    回顾 首先回顾: JDK动态代理与CGLIB动态代理 Spring中的InstantiationAwareBeanPostProcessor和BeanPostProcessor的区别 我们得知 JDK ...

随机推荐

  1. eclipes常见操作总结及项目2和3经验总结

    eclipes常见操作总结及项目2经验总结 eclipes提示: 打开eclipes 选择window->perference->java->editor->content a ...

  2. Oracle列值拼接

    最近在学习的过程中,发现一个挺有意思的函数,它可实现对列值的拼接.下面我们来看看其具体用法. 用法: 对其作用,官方文档的解释如下: For a specified measure, LISTAGG  ...

  3. 学习PHP中的信息格式化操作

    在国际化组件的学习过程中,我们已经接触过了 NumberFormatter 这种数字的格式化操作,它可以让我们将数字转换成标准格式.货币.本地语言等形式.今天我们来学习的是另一种专门用于信息格式化的类 ...

  4. Java基础系列(1)- JDK、JRE、JVM

    Java三大版本(Write Once:Run Anywhere) JavaSE:标准版 JavaME:嵌入式开发 JavaEE:E企业级开发 JDK.JRE.JVM JDK是开发工具包 JRE是编译 ...

  5. OC源码剖析对象的本质

    1. 类的底层实现 先写一个 Person 类: @interface Person : NSObject @property (nonatomic, copy) NSString *p_name; ...

  6. Ubuntu怎么开启/关闭防火墙

    在Ubuntu中,使用sudo ufw status命令查看当前防火墙状态. 不活动,是关闭状态. 在Ubuntu中,使用sudo ufw enable命令来开启防火墙. 在Ubuntu中,使用sud ...

  7. pyqt5无边框拖动

    from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * import sys class ...

  8. requests + 正则表达式 获取 ‘猫眼电影top100’。

    使用 进程池Pool 提高爬取数据的速度. 1 # !/usr/bin/python 2 # -*- coding:utf-8 -*- 3 import requests 4 from request ...

  9. 博客调网易云歌单JS

    <!--音乐--> <link rel="stylesheet" href="https://blog-static.cnblogs.com/files ...

  10. redis无法连接

     Exception in thread "main" redis.clients.jedis.exceptions.JedisDataException: DENIED Redi ...