spring-projects / spring-projects/spring-framework
Spring AOP Proxy Not Working with BeanPostProcessor and FactoryBean Dependencies
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 60.2k
- Forks
- 38.8k
- Avg merge
- 5d 2h
- Merged PRs (30d)
- 27
Description
Description
When using Spring AOP to proxy a HelloService bean in combination with a custom BeanPostProcessor (MyPostProcessor) and a FactoryBean (MyFactoryBean), the AOP proxy is not applied to the target bean. The HelloService bean is returned as a plain Java object without any proxy applied. This issue occurs when the BeanPostProcessor has a dependency on another bean (GoodByeService in this case).
Expected Behavior
The HelloService bean should be proxied by AOP, and the following checks should return true:
AopUtils.isAopProxy(helloService)
AopUtils.isJdkDynamicProxy(helloService) or AopUtils.isCglibProxy(helloService)
The @AfterReturning advice in MyAspect should also be invoked when calling the sayHello method of HelloService.
Actual Behavior
The HelloService bean is not proxied. The following checks return false:
AopUtils.isAopProxy(helloService)
AopUtils.isJdkDynamicProxy(helloService)
AopUtils.isCglibProxy(helloService)
Additionally, the @AfterReturning advice in MyAspect is not invoked.
Steps to Reproduce
Here is a minimal reproducible example:
- POM File
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-aop</artifactId>
<parent>
<groupId>com.cj.lb</groupId>
<artifactId>spring-exploration</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<properties>
<spring-versrion>6.0.11</spring-versrion>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-versrion}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-versrion}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
</dependencies>
</project>
- Configuration Class
@EnableAspectJAutoProxy
@Configuration
@ComponentScan
public class MyConfig {
@Bean
MyPostProcessor myPostProcessor(GoodByeService goodByeService) {
MyPostProcessor myPostProcessor = new MyPostProcessor();
myPostProcessor.setGoodByeService(goodByeService);
return myPostProcessor;
}
@Bean
MyFactoryBean myFactoryBean(HelloService helloService) {
MyFactoryBean myFactoryBean = new MyFactoryBean();
myFactoryBean.setHelloService(helloService);
return myFactoryBean;
}
}
- BeanPostProcessor
public class MyPostProcessor implements Ordered, BeanPostProcessor {
private GoodByeService goodByeService;
public GoodByeService getGoodByeService() {
return goodByeService;
}
public void setGoodByeService(GoodByeService goodByeService) {
this.goodByeService = goodByeService;
}
@Override
public int getOrder() {
return 0;
}
}
- Service Classes
@Service
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello() {
String result = "hello world";
System.out.println(result);
return result;
}
}
@Service
public class GoodByeServiceImpl implements GoodByeService {
@Override
public String sayGoodbye() {
return "Goodbye";
}
}
- FactoryBean
public class MyFactoryBean implements FactoryBean {
private HelloService helloService;
public HelloService getHelloService() {
return helloService;
}
public void setHelloService(HelloService helloService) {
this.helloService = helloService;
}
@Override
public Object getObject() throws Exception {
return new MyBean();
}
@Override
public Class<?> getObjectType() {
return MyBean.class;
}
public static class MyBean {
}
}
- Aspect
@Component
@Aspect
public class MyAspect {
@Pointcut("execution(* com.cj.lb.service.HelloService.sayHello(..))")
public void pointcut() {}
@AfterReturning(pointcut = "pointcut()", returning = "result")
public void afterReturning(JoinPoint jp, Object result) {
System.out.println("my aspect aop ...");
}
}
- Main Class
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
HelloService helloService = context.getBean(HelloService.class);
System.out.println("helloService.getClass() = " + helloService.getClass());
System.out.println("Is AOP Proxy: " + AopUtils.isAopProxy(helloService));
System.out.println("Is JDK Dynamic Proxy: " + AopUtils.isJdkDynamicProxy(helloService));
System.out.println("Is CGLIB Proxy: " + AopUtils.isCglibProxy(helloService));
context.close();
}
}
- Output
helloService.getClass() = class com.cj.lb.service.impl.HelloServiceImpl
Is AOP Proxy: false
Is JDK Dynamic Proxy: false
Is CGLIB Proxy: false
Analysis and Workaround
The issue can be resolved by either of the following:
- Annotating the HelloService dependency in MyFactoryBean with @Lazy.
- Adding a proper generic type declaration for MyFactoryBean.
Question
Why does the presence of a BeanPostProcessor with dependencies interfere with the AOP proxy creation for HelloService? Is this a bug in Spring, or is there a specific configuration requirement that I missed?
Additional Context
This issue seems related to the bean initialization order or proxy creation timing, especially when BeanPostProcessor and FactoryBean dependencies are involved. Further clarification would be appreciated.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the supplied minimal reproducer from MyConfig with AnnotationConfigApplicationContext, then trace how MyPostProcessor's GoodByeService dependency and MyFactoryBean's HelloService dependency affect bean initialization and AOP proxy creation. Compare the behavior with @Lazy and with the generic FactoryBean declaration; done means explaining the cause and whether the configuration is required or Spring should change, using the AopUtils checks and advice invocation as evidence.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100