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 ...
随机推荐
- Mybatis简单查询
目录 前言 一.时间区间查询 1.xml中实现 2. Mybatis Plus 方式 二.模糊查询 1.xml中实现 2. Mybatis Plus 方式 前言 好记性不如烂笔头,记录内容,方便日后 ...
- 6步快速配置Tomcat环境变量(Win10)
一.配置 tomcat环境变量之前先安装jdk和配置jdk的环境变量 1.首先右击我的电脑(此电脑),点击属性,或者也可以从控制面板上打开,如下图,找到系统点击高级系统设置: 2.然后进入系统属性界面 ...
- Java集合:HashMap
Hashmap是一个存储key-value的映射表. 优点: 索引数据快,查找一个数据对的时间复杂度是O(1) 增加.删除一个数据的时间复杂度是O(1) key不能重复,可以存储一个null值 存储: ...
- 洛谷P1449——后缀表达式(栈模拟)
题目描述 所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右新进行(不用考虑运算符的优先级). 如:3*(5–2)+7对应 ...
- PHP设计模式之中介者模式
上回说道,我们在外打工的经常会和一类人有很深的接触,那就是房产中介.大学毕业后马上就能在喜欢的城市买到房子的X二代不在我们的考虑范围内哈.既然需要长期的租房,那么因为工作或者生活的变动,不可避免的一两 ...
- mysql5.7当两个字段名类似,查询时会出错
excepInfo: select id,describe from iwebshop_student_problem where id=256 order by id desc -- You hav ...
- 华为云计算IE面试笔记-FusionCompute上的虚拟机A和虚拟机B不能正常通信,请描述可能的故障点和排除方法(分析虚拟机A和虚拟机B不通)
*快速定位故障点:(考到) ARP:同一二层内可以通过ARP -a命令查询到要访问的主机IP(ARP表项中记录了同一二层中的IP和MAC的对应关系),若查询不到,说明二层出现问题(Vlan 间不通)或 ...
- greedy algorithm, insertion sort, quick sort
always makes the choice that seems to be the best at that moment. Example #1: @function: scheduling ...
- Jmeter监控技术实战
性能测试中监控的意义 为性能分析提供依据 监控方案 serverAgent jmeter的插件,监控颗粒度不高,界面简陋 服务器中启动 jmeter中添加插件 Nmon Grafana 优秀监控方案所 ...
- docker network 参数
一. 格式 docker network COMMAND 二.COMMAND 讲解 2.1 .docker network connect 格式 docker network connect [OPT ...