spring-projects/spring-framework · error · IllegalArgumentException
Aspect class [{aspectClass.getName()}] does not define a sin
Error message
Aspect class [{aspectClass.getName()}] does not define a singleton aspect What it means
Thrown as an IllegalArgumentException from AspectJProxyFactory.addAspect(Object aspectInstance). This overload requires the supplied aspect INSTANCE to be a singleton aspect (per-clause kind SINGLETON), because Spring reuses that single instance across all advised targets. If the aspect class declares perthis/pertarget/pertypewithin/percflow semantics, a single shared instance is semantically invalid, so Spring rejects it.
Source
Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectJProxyFactory.java:96
*/
public AspectJProxyFactory(Class<?>... interfaces) {
setInterfaces(interfaces);
}
/**
* Add the supplied aspect instance to the chain. The type of the aspect instance
* supplied must be a singleton aspect. True singleton lifecycle is not honored when
* using this method - the caller is responsible for managing the lifecycle of any
* aspects added in this way.
* @param aspectInstance the AspectJ aspect instance
*/
public void addAspect(Object aspectInstance) {
Class<?> aspectClass = aspectInstance.getClass();
String aspectName = aspectClass.getName();
AspectMetadata am = createAspectMetadata(aspectClass, aspectName);
if (am.getAjType().getPerClause().getKind() != PerClauseKind.SINGLETON) {
throw new IllegalArgumentException(
"Aspect class [" + aspectClass.getName() + "] does not define a singleton aspect");
}
addAdvisorsFromAspectInstanceFactory(
new SingletonMetadataAwareAspectInstanceFactory(aspectInstance, aspectName));
}
/**
* Add an aspect of the supplied type to the end of the advice chain.
* @param aspectClass the AspectJ aspect class
*/
public void addAspect(Class<?> aspectClass) {
String aspectName = aspectClass.getName();
AspectMetadata am = createAspectMetadata(aspectClass, aspectName);
MetadataAwareAspectInstanceFactory instanceFactory = createAspectInstanceFactory(am, aspectClass, aspectName);
addAdvisorsFromAspectInstanceFactory(instanceFactory);
}
View on GitHub (pinned to 69bf83ad71)
Solutions
- Use the addAspect(Class) overload instead, which supports non-singleton aspects by creating independent instances via a factory.
- Re-annotate the aspect as a plain @Aspect (singleton) if per-object state is not actually required.
- Manage per-object state inside the singleton aspect using ThreadLocal or a keyed map rather than the perthis/pertarget model.
Example fix
// before
@Aspect("pertarget(execution(* com.example.Target.*(..)))")
public class PerTargetAspect { ... }
AspectJProxyFactory factory = new AspectJProxyFactory(target);
factory.addAspect(new PerTargetAspect()); // throws
// after
AspectJProxyFactory factory = new AspectJProxyFactory(target);
factory.addAspect(PerTargetAspect.class); // uses class-based overload Defensive patterns
Strategy: validation
Validate before calling
import org.aspectj.lang.reflect.AjTypeSystem;
import org.aspectj.lang.reflect.PerClauseKind;
public static boolean isSingletonAspect(Class<?> aspectClass) {
return AjTypeSystem.getAjType(aspectClass).getPerClause().getKind() == PerClauseKind.SINGLETON;
}
// before addAspect(instance):
if (!isSingletonAspect(instance.getClass())) {
// use the class-based overload instead
factory.addAspect(instance.getClass());
} else {
factory.addAspect(instance);
} Type guard
import org.aspectj.lang.reflect.AjTypeSystem;
import org.aspectj.lang.reflect.PerClauseKind;
public static boolean canAddAsInstance(Object aspectInstance) {
return AjTypeSystem.getAjType(aspectInstance.getClass())
.getPerClause().getKind() == PerClauseKind.SINGLETON;
} Try / catch
try {
factory.addAspect(aspectInstance);
} catch (IllegalArgumentException ex) {
if (ex.getMessage().contains("does not define a singleton aspect")) {
factory.addAspect(aspectInstance.getClass()); // fallback to class-based
} else throw ex;
} Prevention
- Use addAspect(Class) when unsure about the instantiation model; it handles both singleton and non-singleton aspects.
- Reserve addAspect(Object instance) for singleton aspects whose lifecycle you manage externally.
- Document the singleton-only contract of addAspect(Object) in code comments.
When it happens
Trigger: Calling new AspectJProxyFactory(target).addAspect(myAspectInstance) where myAspectInstance's class is annotated @Aspect("perthis(...)"), @Aspect("pertarget(...)"), @Aspect("pertypewithin(...)"), or any non-singleton per-clause.
Common situations: Passing a pre-built aspect instance to AspectJProxyFactory when the aspect was designed for per-object instantiation; mixing programmatic proxy factory usage with aspects intended for container-managed prototype scope.
Related errors
- {aspectClass.getName()} uses percflow instantiation model: T
- {aspectClass.getName()} uses percflowbelow instantiation mod
- Class [{aspectClass.getName()}] is not a valid aspect type
- PerClause {ajType.getPerClause().getKind()} not supported by
- Bean with name '{beanName}' is a singleton, but aspect insta
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/7e645d2ce9ff3311.
Report an issue: GitHub.