Spring AOP @Before与@After注解未触发问题求助
Spring AOP @Before/@After通知未生效排查
我在简单Java应用中用Spring AOP的@Before和@After注解实现切面编程,希望在makePayment方法执行前后输出对应提示,但实际只输出方法内部内容,AOP通知完全没生效。以下是相关代码、配置和输出情况:
Java类
1. Example17.java
package com.example.controller; import com.example.config.ProjectConfig; import com.example.service.PaymentServiceImpl; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Example17 { public static void main(String[] args) { var context = new AnnotationConfigApplicationContext(ProjectConfig.class); PaymentServiceImpl paymentService = context.getBean(PaymentServiceImpl.class); paymentService.makePayment(); } }
2. MyAspect.java
package com.example.aspects; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component public class MyAspect { @Before("execution(* com.example.service.PaymentServiceImpl.makePayment())") public void printBefore() { System.out.println("Payment Started..."); } @After("execution(* com.example.service.PaymentServiceImpl.makePayment())") public void printAfter() { System.out.println("Payment done...."); } }
3. ProjectConfig.java
package com.example.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @ComponentScan(basePackages = {"com.example.service", "com.example.aspects"}) @EnableAspectJAutoProxy public class ProjectConfig { }
4. PaymentServiceImpl.java
package com.example.service; import org.springframework.stereotype.Component; @Component public class PaymentServiceImpl implements PaymentService { @Override public void makePayment() { System.out.println("Amount Debited"); System.out.println("Amount credited to another account"); } }
POM文件
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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> <groupId>com.springwithshubham</groupId> <artifactId>example-17</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>19</maven.compiler.source> <maven.compiler.target>19</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <!-- Spring Context for ApplicationContext and Component Scanning --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>6.1.10</version> </dependency> <!-- Spring Aspects for AOP support --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>6.1.10</version> </dependency> </dependencies> </project>
预期与实际输出
预期输出
Payment Started... Amount Debited Amount credited to another account Payment done....
实际输出
Amount Debited Amount credited to another account
问题原因及解决方案
核心问题:直接获取实现类对象,绕过Spring代理
Spring AOP默认使用JDK动态代理,该代理基于接口生成。当通过context.getBean(PaymentServiceImpl.class)获取Bean时,Spring无法返回符合实现类类型的代理对象(代理类仅实现PaymentService接口,并非PaymentServiceImpl的子类),因此实际拿到的是原始的PaymentServiceImpl实例,而非代理对象,AOP通知自然不会触发。
解决方案1:通过接口类型获取Bean
修改Example17.java的代码,改用接口类型获取Bean:
package com.example.controller; import com.example.config.ProjectConfig; import com.example.service.PaymentService; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Example17 { public static void main(String[] args) { var context = new AnnotationConfigApplicationContext(ProjectConfig.class); // 改为通过接口类型获取Bean PaymentService paymentService = context.getBean(PaymentService.class); paymentService.makePayment(); } }
解决方案2:强制使用CGLIB代理
若确实需要通过实现类获取Bean,可修改ProjectConfig的@EnableAspectJAutoProxy注解,开启CGLIB代理:
@Configuration @ComponentScan(basePackages = {"com.example.service", "com.example.aspects"}) // proxyTargetClass = true 强制使用CGLIB代理 @EnableAspectJAutoProxy(proxyTargetClass = true) public class ProjectConfig { }
CGLIB通过继承实现类生成代理,此时可直接获取PaymentServiceImpl类型的代理对象,AOP通知会正常生效。
内容的提问来源于stack exchange,提问作者Shubham Jadhav
相关产品推荐
相关产品推荐

