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

  1. Change the aspect instantiation model to singleton by removing the percflow value: use plain @Aspect (equivalent to @Aspect("singleton(...)")).
  2. If per-execution-flow scoping is genuinely required, switch to AspectJ compile-time (ajc) or load-time weaving instead of Spring AOP proxying.
  3. 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

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


AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09). Data as JSON: /api/errors/b84592301b903ebd. Report an issue: GitHub.