admin管理员组文章数量:1416489
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)
orAopUtils.isCglibProxy(helloService)
Additionally, 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=".0.0"
xmlns:xsi=";
xsi:schemaLocation=".0.0 .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>.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-versrion}</version>
</dependency>
<dependency>
<groupId>.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-versrion}</version>
</dependency>
<dependency>
<groupId>.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 inMyFactoryBean
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.
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)
orAopUtils.isCglibProxy(helloService)
Additionally, 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./POM/4.0.0"
xmlns:xsi="http://www.w3./2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache./POM/4.0.0 http://maven.apache./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>.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-versrion}</version>
</dependency>
<dependency>
<groupId>.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-versrion}</version>
</dependency>
<dependency>
<groupId>.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 inMyFactoryBean
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.
1 Answer
Reset to default 2I added src/main/resources/logback.xml to your project as follows to trace bean creation and AOP:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</Pattern>
</layout>
</appender>
<logger name=".springframework.beans" level="DEBUG"/>
<logger name=".springframework.context" level="DEBUG"/>
<logger name=".springframework.aop" level="DEBUG"/>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
Then, I modified your aspect, adding another pointcut + advice to intercept GoodbyeService
, because I wanted to see how it behaves when a proxy ought to be created for it. I also added some more logging to the main program. When running the program without @Lazy
, it prints (timestamps removed to be able to diff it):
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean '.springframework.context.annotation.internalConfigurationAnnotationProcessor'
DEBUG o.s.c.a.ClassPathBeanDefinitionScanner - Identified candidate component class: file [C:\Users\alexa\Documents\java-src\SO_AJ_SpringBeanPostProcessor_79505769\target\classes\com\cj\lb\MyAspect.class]
DEBUG o.s.c.a.ClassPathBeanDefinitionScanner - Identified candidate component class: file [C:\Users\alexa\Documents\java-src\SO_AJ_SpringBeanPostProcessor_79505769\target\classes\com\cj\lb\service\GoodByeServiceImpl.class]
DEBUG o.s.c.a.ClassPathBeanDefinitionScanner - Identified candidate component class: file [C:\Users\alexa\Documents\java-src\SO_AJ_SpringBeanPostProcessor_79505769\target\classes\com\cj\lb\service\HelloServiceImpl.class]
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean '.springframework.context.event.internalEventListenerProcessor'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean '.springframework.context.event.internalEventListenerFactory'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean '.springframework.context.annotation.internalAutowiredAnnotationProcessor'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myPostProcessor'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'helloServiceImpl'
HelloServiceImpl constructor
WARN o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'helloServiceImpl' of type [com.cj.lb.service.HelloServiceImpl] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected/applied to a currently created BeanPostProcessor [myPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies/advisors. If this bean does not have to be post-processed, declare it with ROLE_INFRASTRUCTURE.
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Autowiring by type from bean name 'myFactoryBean' via factory method to bean named 'helloServiceImpl'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'goodByeServiceImpl'
GoodByeServiceImpl constructor
WARN o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'goodByeServiceImpl' of type [com.cj.lb.service.GoodByeServiceImpl] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected/applied to a currently created BeanPostProcessor [myPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies/advisors. If this bean does not have to be post-processed, declare it with ROLE_INFRASTRUCTURE.
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Autowiring by type from bean name 'myPostProcessor' via factory method to bean named 'goodByeServiceImpl'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean '.springframework.aop.config.internalAutoProxyCreator'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myConfig'
DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public void com.cj.lb.MyAspect.goodbyeAdvice(.aspectj.lang.JoinPoint,java.lang.Object)
DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public void com.cj.lb.MyAspect.helloAdvice(.aspectj.lang.JoinPoint,java.lang.Object)
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myAspect'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myFactoryBean'
HelloService class: class com.cj.lb.service.HelloServiceImpl
Is AOP proxy: false
Is JDK proxy: false
Is CGLIB proxy: false
Hello, world!
GoodByeService class: class com.cj.lb.service.GoodByeServiceImpl
Is AOP proxy: false
Is JDK proxy: false
Is CGLIB proxy: false
Goodbye, world!
Now, adding @Lazy
to both bean method parameters in the config class:
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean '.springframework.context.annotation.internalConfigurationAnnotationProcessor'
DEBUG o.s.c.a.ClassPathBeanDefinitionScanner - Identified candidate component class: file [C:\Users\alexa\Documents\java-src\SO_AJ_SpringBeanPostProcessor_79505769\target\classes\com\cj\lb\MyAspect.class]
DEBUG o.s.c.a.ClassPathBeanDefinitionScanner - Identified candidate component class: file [C:\Users\alexa\Documents\java-src\SO_AJ_SpringBeanPostProcessor_79505769\target\classes\com\cj\lb\service\GoodByeServiceImpl.class]
DEBUG o.s.c.a.ClassPathBeanDefinitionScanner - Identified candidate component class: file [C:\Users\alexa\Documents\java-src\SO_AJ_SpringBeanPostProcessor_79505769\target\classes\com\cj\lb\service\HelloServiceImpl.class]
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean '.springframework.context.event.internalEventListenerProcessor'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean '.springframework.context.event.internalEventListenerFactory'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean '.springframework.context.annotation.internalAutowiredAnnotationProcessor'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myPostProcessor'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean '.springframework.aop.config.internalAutoProxyCreator'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myConfig'
DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public void com.cj.lb.MyAspect.goodbyeAdvice(.aspectj.lang.JoinPoint,java.lang.Object)
DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public void com.cj.lb.MyAspect.helloAdvice(.aspectj.lang.JoinPoint,java.lang.Object)
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myAspect'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'goodByeServiceImpl'
GoodByeServiceImpl constructor
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'helloServiceImpl'
HelloServiceImpl constructor
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myFactoryBean'
HelloService class: class jdk.proxy2.$Proxy23
Is AOP proxy: true
Is JDK proxy: true
Is CGLIB proxy: false
Hello, world!
execution(String com.cj.lb.service.HelloService.sayHello())
GoodByeService class: class jdk.proxy2.$Proxy15
Is AOP proxy: true
Is JDK proxy: true
Is CGLIB proxy: false
Goodbye, world!
execution(String com.cj.lb.service.GoodByeService.sayGoodbye())
Please note the main difference in the relative order of these (irrelevant parts of the log removed):
Creating shared instance of singleton bean 'myPostProcessor'
Creating shared instance of singleton bean 'helloServiceImpl'
Creating shared instance of singleton bean 'goodByeServiceImpl'
Creating shared instance of singleton bean 'myAspect'
Creating shared instance of singleton bean 'myFactoryBean'
The aspect is created later than the two beans it is supposed to create proxies for, i.e. they already have been injected into the bean factory and the bean post processor, respectively.
With @Lazy
, it looks better, which explains why it works now:
Creating shared instance of singleton bean 'myPostProcessor'
Creating shared instance of singleton bean 'myAspect'
Creating shared instance of singleton bean 'goodByeServiceImpl'
Creating shared instance of singleton bean 'helloServiceImpl'
Creating shared instance of singleton bean 'myFactoryBean'
本文标签: javaSpring AOP Proxy Not Working with BeanPostProcessor and FactoryBean DependenciesStack Overflow
版权声明:本文标题:java - Spring AOP Proxy Not Working with BeanPostProcessor and FactoryBean Dependencies - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744714206a2621303.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
BeanPostProcessor
s should be registered with astatic
method not an instance method. – M. Deinum Commented Mar 13 at 10:21MyPostProcessor myPostProcessor(@Lazy GoodByeService goodByeService)
andMyFactoryBean myFactoryBean(@Lazy HelloService helloService)
both work. BTW,GoodByeService
will only be a proxy if e.g. targeted by an aspect, which in your example is not the case. There is a Baeldung article explaining and recommending this approach. I am not competent in bean post processors, but I find the explanation comprehensible enough to recommend it. If the link helps you, just let me know and I convert the comment into an answer. – kriegaex Commented Mar 14 at 2:37@Bean
methods in@Configuration
classes ought to be static or not, the Spring manual (search for the info note starting with "You may declare@Bean
methods asstatic
") provides some guidelines for it. – kriegaex Commented Mar 14 at 3:32