You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 21:54:56