Skip to content

Commit c406c56

Browse files
committed
Avoid class loading during AspectJ expression evaluation
Fixed through downcasting to AspectJ's ReflectionType and ReflectionBasedReferenceTypeDelegate, obtaining the myClass field there. We only fall back to regular class loading if we encounter any other kind of type. Issue: SPR-11344
1 parent d9ab6aa commit c406c56

File tree

2 files changed

+121
-100
lines changed

2 files changed

+121
-100
lines changed

spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJExpressionPointcut.java

Lines changed: 57 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -42,6 +42,7 @@
4242
import org.aspectj.weaver.tools.PointcutParser;
4343
import org.aspectj.weaver.tools.PointcutPrimitive;
4444
import org.aspectj.weaver.tools.ShadowMatch;
45+
4546
import org.springframework.aop.ClassFilter;
4647
import org.springframework.aop.IntroductionAwareMethodMatcher;
4748
import org.springframework.aop.MethodMatcher;
@@ -55,6 +56,7 @@
5556
import org.springframework.beans.factory.BeanFactoryUtils;
5657
import org.springframework.beans.factory.FactoryBean;
5758
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
59+
import org.springframework.util.ClassUtils;
5860
import org.springframework.util.ObjectUtils;
5961
import org.springframework.util.StringUtils;
6062

@@ -98,11 +100,11 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
98100

99101
private static final Log logger = LogFactory.getLog(AspectJExpressionPointcut.class);
100102

101-
private Class pointcutDeclarationScope;
103+
private Class<?> pointcutDeclarationScope;
102104

103105
private String[] pointcutParameterNames = new String[0];
104106

105-
private Class[] pointcutParameterTypes = new Class[0];
107+
private Class<?>[] pointcutParameterTypes = new Class<?>[0];
106108

107109
private BeanFactory beanFactory;
108110

@@ -123,7 +125,7 @@ public AspectJExpressionPointcut() {
123125
* @param paramNames the parameter names for the pointcut
124126
* @param paramTypes the parameter types for the pointcut
125127
*/
126-
public AspectJExpressionPointcut(Class declarationScope, String[] paramNames, Class[] paramTypes) {
128+
public AspectJExpressionPointcut(Class<?> declarationScope, String[] paramNames, Class<?>[] paramTypes) {
127129
this.pointcutDeclarationScope = declarationScope;
128130
if (paramNames.length != paramTypes.length) {
129131
throw new IllegalStateException(
@@ -137,21 +139,21 @@ public AspectJExpressionPointcut(Class declarationScope, String[] paramNames, Cl
137139
/**
138140
* Set the declaration scope for the pointcut.
139141
*/
140-
public void setPointcutDeclarationScope(Class pointcutDeclarationScope) {
142+
public void setPointcutDeclarationScope(Class<?> pointcutDeclarationScope) {
141143
this.pointcutDeclarationScope = pointcutDeclarationScope;
142144
}
143145

144146
/**
145147
* Set the parameter names for the pointcut.
146148
*/
147-
public void setParameterNames(String[] names) {
149+
public void setParameterNames(String... names) {
148150
this.pointcutParameterNames = names;
149151
}
150152

151153
/**
152154
* Set the parameter types for the pointcut.
153155
*/
154-
public void setParameterTypes(Class[] types) {
156+
public void setParameterTypes(Class<?>... types) {
155157
this.pointcutParameterTypes = types;
156158
}
157159

@@ -188,9 +190,9 @@ private void checkReadyToMatch() {
188190
* Build the underlying AspectJ pointcut expression.
189191
*/
190192
private PointcutExpression buildPointcutExpression() {
191-
ClassLoader cl = (this.beanFactory instanceof ConfigurableBeanFactory ? ((ConfigurableBeanFactory) this.beanFactory)
192-
.getBeanClassLoader() : Thread.currentThread()
193-
.getContextClassLoader());
193+
ClassLoader cl = (this.beanFactory instanceof ConfigurableBeanFactory ?
194+
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
195+
ClassUtils.getDefaultClassLoader());
194196
return buildPointcutExpression(cl);
195197
}
196198

@@ -202,8 +204,7 @@ private PointcutExpression buildPointcutExpression(ClassLoader classLoader) {
202204
PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
203205
for (int i = 0; i < pointcutParameters.length; i++) {
204206
pointcutParameters[i] = parser.createPointcutParameter(
205-
this.pointcutParameterNames[i],
206-
this.pointcutParameterTypes[i]);
207+
this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
207208
}
208209
return parser.parsePointcutExpression(
209210
replaceBooleanOperators(getExpression()),
@@ -244,20 +245,19 @@ public PointcutExpression getPointcutExpression() {
244245
return this.pointcutExpression;
245246
}
246247

247-
public boolean matches(Class targetClass) {
248+
public boolean matches(Class<?> targetClass) {
248249
checkReadyToMatch();
249250
try {
250251
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
251-
} catch (ReflectionWorldException e) {
252-
logger.debug("PointcutExpression matching rejected target class", e);
252+
}
253+
catch (ReflectionWorldException rwe) {
254+
logger.debug("PointcutExpression matching rejected target class", rwe);
253255
try {
254-
// Actually this is still a "maybe" - treat the pointcut as dynamic if we
255-
// don't know enough yet
256+
// Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
256257
return getFallbackPointcutExpression(targetClass).couldMatchJoinPointsInType(targetClass);
257-
} catch (BCException ex) {
258-
logger.debug(
259-
"Fallback PointcutExpression matching rejected target class",
260-
ex);
258+
}
259+
catch (BCException bce) {
260+
logger.debug("Fallback PointcutExpression matching rejected target class", bce);
261261
return false;
262262
}
263263
}
@@ -267,7 +267,7 @@ public boolean matches(Class targetClass) {
267267
}
268268
}
269269

270-
public boolean matches(Method method, Class targetClass, boolean beanHasIntroductions) {
270+
public boolean matches(Method method, Class<?> targetClass, boolean beanHasIntroductions) {
271271
checkReadyToMatch();
272272
Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
273273
ShadowMatch shadowMatch = getShadowMatch(targetMethod, method);
@@ -283,11 +283,19 @@ else if (shadowMatch.neverMatches()) {
283283
}
284284
else {
285285
// the maybe case
286-
return (beanHasIntroductions || matchesIgnoringSubtypes(shadowMatch) || matchesTarget(shadowMatch, targetClass));
286+
if (beanHasIntroductions) {
287+
return true;
288+
}
289+
// A match test returned maybe - if there are any subtype sensitive variables
290+
// involved in the test (this, target, at_this, at_target, at_annotation) then
291+
// we say this is not a match as in Spring there will never be a different
292+
// runtime subtype.
293+
RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
294+
return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
287295
}
288296
}
289297

290-
public boolean matches(Method method, Class targetClass) {
298+
public boolean matches(Method method, Class<?> targetClass) {
291299
return matches(method, targetClass, false);
292300
}
293301

@@ -296,7 +304,7 @@ public boolean isRuntime() {
296304
return this.pointcutExpression.mayNeedDynamicTest();
297305
}
298306

299-
public boolean matches(Method method, Class targetClass, Object[] args) {
307+
public boolean matches(Method method, Class<?> targetClass, Object[] args) {
300308
checkReadyToMatch();
301309
ShadowMatch shadowMatch = getShadowMatch(AopUtils.getMostSpecificMethod(method, targetClass), method);
302310
ShadowMatch originalShadowMatch = getShadowMatch(method, method);
@@ -336,14 +344,13 @@ public boolean matches(Method method, Class targetClass, Object[] args) {
336344
if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
337345
return false;
338346
}
339-
}
340-
if (joinPointMatch.matches() && pmi != null) {
341-
bindParameters(pmi, joinPointMatch);
347+
if (joinPointMatch.matches()) {
348+
bindParameters(pmi, joinPointMatch);
349+
}
342350
}
343351
return joinPointMatch.matches();
344352
}
345353

346-
347354
protected String getCurrentProxiedBeanName() {
348355
return ProxyCreationContext.getCurrentProxiedBeanName();
349356
}
@@ -353,29 +360,14 @@ protected String getCurrentProxiedBeanName() {
353360
* Get a new pointcut expression based on a target class's loader, rather
354361
* than the default.
355362
*/
356-
private PointcutExpression getFallbackPointcutExpression(
357-
Class<?> targetClass) {
363+
private PointcutExpression getFallbackPointcutExpression(Class<?> targetClass) {
358364
ClassLoader classLoader = targetClass.getClassLoader();
359-
return classLoader == null ? this.pointcutExpression : buildPointcutExpression(classLoader);
360-
}
361-
362-
/**
363-
* A match test returned maybe - if there are any subtype sensitive variables
364-
* involved in the test (this, target, at_this, at_target, at_annotation) then
365-
* we say this is not a match as in Spring there will never be a different
366-
* runtime subtype.
367-
*/
368-
private boolean matchesIgnoringSubtypes(ShadowMatch shadowMatch) {
369-
return !(getRuntimeTestWalker(shadowMatch).testsSubtypeSensitiveVars());
370-
}
371-
372-
private boolean matchesTarget(ShadowMatch shadowMatch, Class targetClass) {
373-
return getRuntimeTestWalker(shadowMatch).testTargetInstanceOfResidue(targetClass);
365+
return (classLoader != null ? buildPointcutExpression(classLoader) : this.pointcutExpression);
374366
}
375367

376368
private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) {
377369
if (shadowMatch instanceof DefensiveShadowMatch) {
378-
return new RuntimeTestWalker(((DefensiveShadowMatch)shadowMatch).primary);
370+
return new RuntimeTestWalker(((DefensiveShadowMatch) shadowMatch).primary);
379371
}
380372
return new RuntimeTestWalker(shadowMatch);
381373
}
@@ -409,29 +401,31 @@ private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) {
409401
try {
410402
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
411403
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
412-
} catch (ReflectionWorld.ReflectionWorldException e) {
404+
}
405+
catch (ReflectionWorld.ReflectionWorldException ex2) {
413406
if (targetMethod == originalMethod) {
414407
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
415408
}
416409
else {
417410
try {
418411
shadowMatch = this.pointcutExpression.matchesMethodExecution(originalMethod);
419412
}
420-
catch (ReflectionWorld.ReflectionWorldException ex2) {
413+
catch (ReflectionWorld.ReflectionWorldException ex3) {
421414
// Could neither introspect the target class nor the proxy class ->
422415
// let's simply consider this method as non-matching.
423416
methodToMatch = originalMethod;
424417
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
425418
try {
426419
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
427-
} catch (ReflectionWorld.ReflectionWorldException e2) {
420+
}
421+
catch (ReflectionWorld.ReflectionWorldException ex4) {
428422
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
429423
}
430424
}
431425
}
432426
}
433427
}
434-
if (shadowMatch.maybeMatches() && fallbackPointcutExpression!=null) {
428+
if (shadowMatch.maybeMatches() && fallbackPointcutExpression != null) {
435429
shadowMatch = new DefensiveShadowMatch(shadowMatch,
436430
fallbackPointcutExpression.matchesMethodExecution(methodToMatch));
437431
}
@@ -601,9 +595,11 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound
601595
this.shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
602596
}
603597

598+
604599
private static class DefensiveShadowMatch implements ShadowMatch {
605600

606601
private final ShadowMatch primary;
602+
607603
private final ShadowMatch other;
608604

609605
public DefensiveShadowMatch(ShadowMatch primary, ShadowMatch other) {
@@ -612,31 +608,30 @@ public DefensiveShadowMatch(ShadowMatch primary, ShadowMatch other) {
612608
}
613609

614610
public boolean alwaysMatches() {
615-
return primary.alwaysMatches();
611+
return this.primary.alwaysMatches();
616612
}
617613

618614
public boolean maybeMatches() {
619-
return primary.maybeMatches();
615+
return this.primary.maybeMatches();
620616
}
621617

622618
public boolean neverMatches() {
623-
return primary.neverMatches();
619+
return this.primary.neverMatches();
624620
}
625621

626-
public JoinPointMatch matchesJoinPoint(Object thisObject,
627-
Object targetObject, Object[] args) {
622+
public JoinPointMatch matchesJoinPoint(Object thisObject, Object targetObject, Object[] args) {
628623
try {
629-
return primary.matchesJoinPoint(thisObject, targetObject, args);
630-
} catch (ReflectionWorldException e) {
631-
return other.matchesJoinPoint(thisObject, targetObject, args);
624+
return this.primary.matchesJoinPoint(thisObject, targetObject, args);
625+
}
626+
catch (ReflectionWorldException ex) {
627+
return this.other.matchesJoinPoint(thisObject, targetObject, args);
632628
}
633629
}
634630

635631
public void setMatchingContext(MatchingContext aMatchContext) {
636-
primary.setMatchingContext(aMatchContext);
637-
other.setMatchingContext(aMatchContext);
632+
this.primary.setMatchingContext(aMatchContext);
633+
this.other.setMatchingContext(aMatchContext);
638634
}
639-
640635
}
641636

642637
}

0 commit comments

Comments
 (0)