Skip to content

Spring AOP Proxy Not Working with BeanPostProcessor and FactoryBean Dependencies #34563

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
java-lbb opened this issue Mar 10, 2025 · 2 comments
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: waiting-for-triage An issue we've not yet triaged or decided on

Comments

@java-lbb
Copy link

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.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Mar 10, 2025
@sbrannen sbrannen added the in: core Issues in core modules (aop, beans, core, context, expression) label Mar 10, 2025
@kriegaex
Copy link
Contributor

@java-lbb cross-posted this on Stack Overflow where I answered with some additional analysis, e.g. explaining how @Lazy can help to work around the problem.

For your convenience, a reproducer is here:
https://github.com/kriegaex/SO_AJ_SpringBeanPostProcessor_79505769

Activating @Lazy in both bean methods here makes the problem go away.

If you want to compare the extended log output for both variants, diff files

to each other.

@kriegaex
Copy link
Contributor

Linking back to #34735, if it helps to have a reproducer. It is yet to be determined by the Spring developers, if these two issues are actually related.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: waiting-for-triage An issue we've not yet triaged or decided on
Projects
None yet
Development

No branches or pull requests

4 participants