spring-projects/spring-framework · error · AopConfigException
{aspectClass.getName()} uses percflow instantiation model: T
Error message
{aspectClass.getName()} uses percflow instantiation model: This is not supported in Spring AOP. What it means
Thrown by AbstractAspectJAdvisorFactory.validate() as an AopConfigException when the aspect's per-clause kind is PerClauseKind.PERCFLOW. Spring AOP's proxy-based model only supports singleton, perthis, pertarget, and pertypewithin instantiation; percflow (one aspect instance per flow/control-flow entry) requires load-time or compile-time AspectJ weaving and cannot be implemented with proxies. This check rejects such aspects early before advisor construction.
Source
Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java:100
protected final Log logger = LogFactory.getLog(getClass());
protected final ParameterNameDiscoverer parameterNameDiscoverer = new AspectJAnnotationParameterNameDiscoverer();
@Override
public boolean isAspect(Class<?> clazz) {
return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null &&
(!shouldIgnoreAjcCompiledAspects || !compiledByAjc(clazz)));
}
@Override
public void validate(Class<?> aspectClass) throws AopConfigException {
AjType<?> ajType = AjTypeSystem.getAjType(aspectClass);
if (!ajType.isAspect()) {
throw new NotAnAtAspectException(aspectClass);
}
if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOW) {
throw new AopConfigException(aspectClass.getName() + " uses percflow instantiation model: " +
"This is not supported in Spring AOP.");
}
if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOWBELOW) {
throw new AopConfigException(aspectClass.getName() + " uses percflowbelow instantiation model: " +
"This is not supported in Spring AOP.");
}
}
/**
* Find and return the first AspectJ annotation on the given method
* (there <i>should</i> only be one anyway...).
*/
@SuppressWarnings("unchecked")
protected static @Nullable AspectJAnnotation findAspectJAnnotationOnMethod(Method method) {
for (Class<?> annotationType : ASPECTJ_ANNOTATION_CLASSES) {
AspectJAnnotation annotation = findAnnotation(method, (Class<Annotation>) annotationType);
if (annotation != null) {View on GitHub (pinned to 69bf83ad71)
Solutions
- Change the aspect instantiation model to singleton by removing the percflow value: use plain @Aspect (equivalent to @Aspect("singleton(...)")).
- If per-execution-flow scoping is genuinely required, switch to AspectJ compile-time (ajc) or load-time weaving instead of Spring AOP proxying.
- If you need per-call state, simulate it with a ThreadLocal field inside a singleton aspect.
Example fix
// before
@Aspect("percflow(execution(* com.example.Service.*(..)))")
public class FlowAspect { ... }
// after
@Aspect
public class FlowAspect {
private final ThreadLocal<Deque<Object>> flowState = new ThreadLocal<>();
...
} Defensive patterns
Strategy: validation
Validate before calling
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.AjTypeSystem;
import org.aspectj.lang.reflect.PerClauseKind;
public static boolean isSpringAopCompatible(Class<?> aspectClass) {
var kind = AjTypeSystem.getAjType(aspectClass).getPerClause().getKind();
return kind != PerClauseKind.PERCFLOW && kind != PerClauseKind.PERCFLOWBELOW;
}
if (!isSpringAopCompatible(MyAspect.class)) {
throw new IllegalStateException("Aspect uses an unsupported per-clause for Spring AOP");
} Type guard
import org.aspectj.lang.reflect.AjTypeSystem;
import org.aspectj.lang.reflect.PerClauseKind;
public static boolean isPercflow(Class<?> c) {
return AjTypeSystem.getAjType(c).getPerClause().getKind() == PerClauseKind.PERCFLOW;
} Try / catch
try {
advisorFactory.validate(aspectClass);
} catch (AopConfigException ex) {
if (ex.getMessage().contains("percflow")) {
// rewrite the aspect or switch to AspectJ weaving
} else throw ex;
} Prevention
- Avoid @Aspect("percflow(...)") and @Aspect("percflowbelow(...)") in Spring AOP projects.
- Document which per-clauses Spring AOP supports (singleton, perthis, pertarget, pertypewithin) in a project ADR.
- When importing aspects from AspectJ-native projects, audit their per-clauses.
When it happens
Trigger: Annotating a class with @Aspect("percflow(pointcut)") and submitting it to Spring AOP via @EnableAspectJAutoProxy, AspectJProxyFactory.addAspect(...), or a BeanFactoryAspectJAdvisorsBuilder; calling advisorFactory.validate(aspectClass) on such a class.
Common situations: Porting an AspectJ aspect written for native AspectJ weaving into a Spring AOP application without changing the per-clause; copy-pasting an aspect from an AspectJ tutorial that uses percflow; upgrading a project where previously only AspectJ weaving was used and now @EnableAspectJAutoProxy is also active.
Related errors
- {aspectClass.getName()} uses percflowbelow instantiation mod
- PerClause {ajType.getPerClause().getKind()} not supported by
- Bean with name '{beanName}' is a singleton, but aspect insta
- 'argumentNames' property of AbstractAspectJAdvice contains a
- Only afterReturning advice can be used to bind a return valu
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/b84592301b903ebd.
Report an issue: GitHub.