spring-framework icon indicating copy to clipboard operation
spring-framework copied to clipboard

Spring AOP Proxy Not Working with BeanPostProcessor and FactoryBean Dependencies

Open java-lbb opened this issue 9 months ago • 8 comments

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:

  1. 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>
  1. 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;
    }
}
  1. 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;
    }
}
  1. 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";
    }
}
  1. 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 {
    }
}
  1. 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 ...");
    }
}
  1. 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();
    }
}
  1. 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:

  1. Annotating the HelloService dependency in MyFactoryBean with @Lazy.
  2. 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.

java-lbb avatar Mar 10 '25 10:03 java-lbb