spring-projects/spring-framework · error · IllegalStateException
BeanFactory must be set on {getClass().getSimpleName()} to a
Error message
BeanFactory must be set on {getClass().getSimpleName()} to access qualified executor '{qualifier}' What it means
Thrown by findQualifiedExecutor when an async method carries an executor qualifier (e.g. @Async("customExecutor")) but the aspect's BeanFactory was never injected. Resolving a qualified executor requires a BeanFactory to look the bean up by type+qualifier; without one the lookup cannot proceed. The class name in the message is the concrete aspect subclass (AnnotationAsyncExecutionInterceptor, an AspectJ aspect, etc.).
Source
Thrown at spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java:214
* been specified and that the {@linkplain #setExecutor(Executor) default executor}
* should be used.
* @param method the method to inspect for executor qualifier metadata
* @return the qualifier if specified, otherwise empty String or {@code null}
* @see #determineAsyncExecutor(Method)
* @see #findQualifiedExecutor(BeanFactory, String)
*/
protected abstract @Nullable String getExecutorQualifier(Method method);
/**
* Retrieve a target executor for the given qualifier.
* @param qualifier the qualifier to resolve
* @return the target executor, or {@code null} if none available
* @since 4.2.6
* @see #getExecutorQualifier(Method)
*/
protected @Nullable Executor findQualifiedExecutor(@Nullable BeanFactory beanFactory, String qualifier) {
if (beanFactory == null) {
throw new IllegalStateException("BeanFactory must be set on " + getClass().getSimpleName() +
" to access qualified executor '" + qualifier + "'");
}
return BeanFactoryAnnotationUtils.qualifiedBeanOfType(beanFactory, Executor.class, qualifier);
}
/**
* Retrieve or build a default executor for this advice instance.
* <p>An executor returned from here will be cached for further use.
* <p>The default implementation searches for a unique {@link TaskExecutor} bean
* in the context, or for an {@link Executor} bean named "taskExecutor" otherwise.
* If neither of the two is resolvable, this implementation will return {@code null}.
* @param beanFactory the BeanFactory to use for a default executor lookup
* @return the default executor, or {@code null} if none available
* @since 4.2.6
* @see #findQualifiedExecutor(BeanFactory, String)
* @see #DEFAULT_TASK_EXECUTOR_BEAN_NAME
*/
protected @Nullable Executor getDefaultExecutor(@Nullable BeanFactory beanFactory) {View on GitHub (pinned to e8729d0438)
Solutions
- Register the async aspect/interceptor as a Spring bean so the container invokes setBeanFactory automatically (e.g. via @EnableAsync or <task:annotation-driven/>).
- If constructing programmatically, call aspect.setBeanFactory(applicationContext) explicitly before any async invocation.
- Drop the qualifier from @Async so the default-executor path (which does not need a BeanFactory) is used, or pass a concrete Executor to setExecutor().
Example fix
// before
AsyncExecutionInterceptor aspect = new AsyncExecutionInterceptor();
advisor = new DefaultPointcutAdvisor(pointcut, aspect);
// beanFactory never set -> error 100 on @Async("poolA")
// after
AsyncExecutionInterceptor aspect = new AsyncExecutionInterceptor();
aspect.setBeanFactory(applicationContext);
advisor = new DefaultPointcutAdvisor(pointcut, aspect); Defensive patterns
Strategy: validation
Validate before calling
// before relying on a qualified executor, confirm the aspect has a BeanFactory
if (aspect instanceof BeanFactoryAware && applicationContext != null) {
aspect.setBeanFactory(applicationContext);
}
// or, when scanning for @Async qualifiers, ensure the owning bean is Spring-managed:
boolean managed = applicationContext.containsBeanDefinition(beanName); Prevention
- Always register async aspects/interceptors as Spring beans instead of constructing them with new.
- Enable @Async through @EnableAsync or <task:annotation-driven/> so setBeanFactory runs automatically.
- Document that any @Async qualifier requires a Spring-managed aspect.
When it happens
Trigger: Invoking an @Async method whose qualifier is non-empty while the AsyncExecutionAspectSupport instance was built programmatically and never had setBeanFactory(BeanFactory) called. Also fires when an AnnotationAsyncExecutionAspect (AspectJ) is woven but not registered as a Spring bean.
Common situations: Manually new-ing an AsyncExecutionInterceptor/Aspect instead of letting <task:annotation-driven/> or @EnableAsync wire it; using AspectJ load-time weaving for @Async without the Spring container managing the aspect; qualifier typo that still resolves to a non-empty string.
Related errors
- No executor specified and no default executor set on AsyncEx
- Not running in a ConfigurableBeanFactory: {beanFactory}
- MethodInvocation is not a Spring ProxyMethodInvocation: {}
- '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@e8729d0438 (2026-08-04).
Data as JSON: /data/errors/08f29af12af7c707.json.
Report an issue: GitHub.