Skip to content

Commit 628b050

Browse files
committed
Skip ajc-compiled aspects for ajc-compiled target classes
Includes defensive ignoring of incompatible aspect types. Closes gh-32970 (cherry picked from commit 0ea96b4)
1 parent 8b589db commit 628b050

File tree

3 files changed

+56
-22
lines changed

3 files changed

+56
-22
lines changed

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

+21-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.io.IOException;
2020
import java.io.ObjectInputStream;
21+
import java.lang.reflect.Field;
2122
import java.lang.reflect.Method;
2223
import java.lang.reflect.Proxy;
2324
import java.util.Arrays;
@@ -85,6 +86,8 @@
8586
public class AspectJExpressionPointcut extends AbstractExpressionPointcut
8687
implements ClassFilter, IntroductionAwareMethodMatcher, BeanFactoryAware {
8788

89+
private static final String AJC_MAGIC = "ajc$";
90+
8891
private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = Set.of(
8992
PointcutPrimitive.EXECUTION,
9093
PointcutPrimitive.ARGS,
@@ -102,6 +105,8 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
102105
@Nullable
103106
private Class<?> pointcutDeclarationScope;
104107

108+
private boolean aspectCompiledByAjc;
109+
105110
private String[] pointcutParameterNames = new String[0];
106111

107112
private Class<?>[] pointcutParameterTypes = new Class<?>[0];
@@ -133,7 +138,7 @@ public AspectJExpressionPointcut() {
133138
* @param paramTypes the parameter types for the pointcut
134139
*/
135140
public AspectJExpressionPointcut(Class<?> declarationScope, String[] paramNames, Class<?>[] paramTypes) {
136-
this.pointcutDeclarationScope = declarationScope;
141+
setPointcutDeclarationScope(declarationScope);
137142
if (paramNames.length != paramTypes.length) {
138143
throw new IllegalStateException(
139144
"Number of pointcut parameter names must match number of pointcut parameter types");
@@ -148,6 +153,7 @@ public AspectJExpressionPointcut(Class<?> declarationScope, String[] paramNames,
148153
*/
149154
public void setPointcutDeclarationScope(Class<?> pointcutDeclarationScope) {
150155
this.pointcutDeclarationScope = pointcutDeclarationScope;
156+
this.aspectCompiledByAjc = compiledByAjc(pointcutDeclarationScope);
151157
}
152158

153159
/**
@@ -273,6 +279,11 @@ public PointcutExpression getPointcutExpression() {
273279
@Override
274280
public boolean matches(Class<?> targetClass) {
275281
if (this.pointcutParsingFailed) {
282+
// Pointcut parsing failed before below -> avoid trying again.
283+
return false;
284+
}
285+
if (this.aspectCompiledByAjc && compiledByAjc(targetClass)) {
286+
// ajc-compiled aspect class for ajc-compiled target class -> already weaved.
276287
return false;
277288
}
278289

@@ -528,6 +539,15 @@ else if (shadowMatch.maybeMatches() && fallbackExpression != null) {
528539
return shadowMatch;
529540
}
530541

542+
private static boolean compiledByAjc(Class<?> clazz) {
543+
for (Field field : clazz.getDeclaredFields()) {
544+
if (field.getName().startsWith(AJC_MAGIC)) {
545+
return true;
546+
}
547+
}
548+
return false;
549+
}
550+
531551

532552
@Override
533553
public boolean equals(@Nullable Object other) {

spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectJAdvisorsBuilder.java

+31-19
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2024 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.
@@ -22,9 +22,12 @@
2222
import java.util.Map;
2323
import java.util.concurrent.ConcurrentHashMap;
2424

25+
import org.apache.commons.logging.Log;
26+
import org.apache.commons.logging.LogFactory;
2527
import org.aspectj.lang.reflect.PerClauseKind;
2628

2729
import org.springframework.aop.Advisor;
30+
import org.springframework.aop.framework.AopConfigException;
2831
import org.springframework.beans.factory.BeanFactoryUtils;
2932
import org.springframework.beans.factory.ListableBeanFactory;
3033
import org.springframework.lang.Nullable;
@@ -40,6 +43,8 @@
4043
*/
4144
public class BeanFactoryAspectJAdvisorsBuilder {
4245

46+
private static final Log logger = LogFactory.getLog(BeanFactoryAspectJAdvisorsBuilder.class);
47+
4348
private final ListableBeanFactory beanFactory;
4449

4550
private final AspectJAdvisorFactory advisorFactory;
@@ -102,30 +107,37 @@ public List<Advisor> buildAspectJAdvisors() {
102107
continue;
103108
}
104109
if (this.advisorFactory.isAspect(beanType)) {
105-
aspectNames.add(beanName);
106-
AspectMetadata amd = new AspectMetadata(beanType, beanName);
107-
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
108-
MetadataAwareAspectInstanceFactory factory =
109-
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
110-
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
111-
if (this.beanFactory.isSingleton(beanName)) {
112-
this.advisorsCache.put(beanName, classAdvisors);
110+
try {
111+
AspectMetadata amd = new AspectMetadata(beanType, beanName);
112+
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
113+
MetadataAwareAspectInstanceFactory factory =
114+
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
115+
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
116+
if (this.beanFactory.isSingleton(beanName)) {
117+
this.advisorsCache.put(beanName, classAdvisors);
118+
}
119+
else {
120+
this.aspectFactoryCache.put(beanName, factory);
121+
}
122+
advisors.addAll(classAdvisors);
113123
}
114124
else {
125+
// Per target or per this.
126+
if (this.beanFactory.isSingleton(beanName)) {
127+
throw new IllegalArgumentException("Bean with name '" + beanName +
128+
"' is a singleton, but aspect instantiation model is not singleton");
129+
}
130+
MetadataAwareAspectInstanceFactory factory =
131+
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
115132
this.aspectFactoryCache.put(beanName, factory);
133+
advisors.addAll(this.advisorFactory.getAdvisors(factory));
116134
}
117-
advisors.addAll(classAdvisors);
135+
aspectNames.add(beanName);
118136
}
119-
else {
120-
// Per target or per this.
121-
if (this.beanFactory.isSingleton(beanName)) {
122-
throw new IllegalArgumentException("Bean with name '" + beanName +
123-
"' is a singleton, but aspect instantiation model is not singleton");
137+
catch (IllegalArgumentException | IllegalStateException | AopConfigException ex) {
138+
if (logger.isDebugEnabled()) {
139+
logger.debug("Ignoring incompatible aspect [" + beanType.getName() + "]: " + ex);
124140
}
125-
MetadataAwareAspectInstanceFactory factory =
126-
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
127-
this.aspectFactoryCache.put(beanName, factory);
128-
advisors.addAll(this.advisorFactory.getAdvisors(factory));
129141
}
130142
}
131143
}

spring-aspects/src/test/resources/org/springframework/aop/aspectj/autoproxy/ajcAutoproxyTests.xml

+4-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
<property name="foo" value="bar"/>
2222
</bean>
2323

24-
<bean id="otherBean" class="java.lang.Object"/>
24+
<bean id="otherBean" class="org.springframework.beans.factory.aspectj.ShouldBeConfiguredBySpring"/>
2525

26-
<bean id="yetAnotherBean" class="java.lang.Object"/>
26+
<bean id="yetAnotherBean" class="org.springframework.beans.factory.aspectj.ShouldBeConfiguredBySpring"/>
27+
28+
<bean id="configuredBean" class="org.springframework.beans.factory.aspectj.ShouldBeConfiguredBySpring" lazy-init="true"/>
2729

2830
</beans>

0 commit comments

Comments
 (0)