spring-projects/spring-framework · error · IllegalArgumentException

Bean with name '{beanName}' is a singleton, but aspect insta

Error message

Bean with name '{beanName}' is a singleton, but aspect instantiation model is not singleton

What it means

Thrown as an IllegalArgumentException from BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors() when an aspect bean declares a non-singleton per-clause (perthis/pertarget/pertypewithin) but the bean itself is registered as a singleton in the BeanFactory. The two are contradictory: a per-object aspect must produce a new instance per target, which a singleton-scoped bean cannot do. Spring catches this mismatch before attempting prototype-based instantiation.

Source

Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectJAdvisorsBuilder.java:126

						if (this.advisorFactory.isAspect(beanType)) {
							try {
								AspectMetadata amd = new AspectMetadata(beanType, beanName);
								if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
									MetadataAwareAspectInstanceFactory factory =
											new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
									List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
									if (this.beanFactory.isSingleton(beanName)) {
										this.advisorsCache.put(beanName, classAdvisors);
									}
									else {
										this.aspectFactoryCache.put(beanName, factory);
									}
									advisors.addAll(classAdvisors);
								}
								else {
									// Per target or per this.
									if (this.beanFactory.isSingleton(beanName)) {
										throw new IllegalArgumentException("Bean with name '" + beanName +
												"' is a singleton, but aspect instantiation model is not singleton");
									}
									MetadataAwareAspectInstanceFactory factory =
											new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
									this.aspectFactoryCache.put(beanName, factory);
									advisors.addAll(this.advisorFactory.getAdvisors(factory));
								}
								aspectNames.add(beanName);
							}
							catch (IllegalArgumentException | IllegalStateException | AopConfigException ex) {
								if (logger.isDebugEnabled()) {
									logger.debug("Ignoring incompatible aspect [" + beanType.getName() + "]: " + ex);
								}
							}
						}
					}
					this.aspectBeanNames = aspectNames;
					return advisors;

View on GitHub (pinned to 69bf83ad71)

Solutions

  1. Annotate the aspect bean with @Scope("prototype") so each advised target gets its own instance.
  2. Alternatively, change the aspect per-clause to singleton if per-object state is unnecessary.
  3. In XML, set scope="prototype" on the aspect bean definition.

Example fix

// before
@Aspect("pertarget(execution(* com.example.Target.*(..)))")
@Component
public class PerTargetAspect { ... } // singleton by default -> throws
// after
import org.springframework.context.annotation.Scope;

@Aspect("pertarget(execution(* com.example.Target.*(..)))")
@Component
@Scope("prototype")
public class PerTargetAspect { ... }
Defensive patterns

Strategy: validation

Validate before calling

import org.aspectj.lang.reflect.AjTypeSystem;
import org.aspectj.lang.reflect.PerClauseKind;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;

public static String requiredScope(Class<?> aspectClass) {
    var kind = AjTypeSystem.getAjType(aspectClass).getPerClause().getKind();
    return (kind == PerClauseKind.SINGLETON)
        ? ConfigurableBeanFactory.SCOPE_SINGLETON
        : ConfigurableBeanFactory.SCOPE_PROTOTYPE;
}

// for a perthis/pertarget aspect bean, ensure scope is prototype before context refresh.

Type guard

import org.aspectj.lang.reflect.AjTypeSystem;
import org.aspectj.lang.reflect.PerClauseKind;

public static boolean needsPrototypeScope(Class<?> aspectClass) {
    var k = AjTypeSystem.getAjType(aspectClass).getPerClause().getKind();
    return k == PerClauseKind.PERTHIS || k == PerClauseKind.PERTARGET || k == PerClauseKind.PERTYPEWITHIN;
}

Try / catch

// BeanFactoryAspectJAdvisorsBuilder catches IllegalArgumentException/IllegalStateException/AopConfigException
// itself and logs at debug; raise logging to DEBUG to surface such incompatible aspects.
// Otherwise validate bean scopes up front (see validationCode).

Prevention

When it happens

Trigger: Declaring a bean annotated @Aspect("perthis(...)") or @Aspect("pertarget(...)") without setting @Scope("prototype"); XML bean declaration with singleton='true' (the default) whose class is a perthis/pertarget aspect; a @Configuration @Bean method returning a non-singleton aspect without specifying prototype scope.

Common situations: Forgetting to add @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) on a perthis/pertarget aspect; copy-pasting an aspect that worked under native AspectJ (where Spring scope is irrelevant) into a Spring AOP auto-proxy context.

Related errors


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