【问题标题】:Why is this Spring Aspect not printing as it should with method parameter?为什么这个 Spring Aspect 没有像使用方法参数那样打印?
【发布时间】:2026-02-27 07:40:01
【问题描述】:

让我首先指出,我面临的问题是
interceptThoughts(String thoughts)
方法,从第一个代码块开始,而不是打印

我正在运行 Spring in Action 的教程。有一个Magician 类与implements MindReader 接口与方法interceptThoughts(String thoughts)getThoughts()

@Aspect
public class Magician implements MindReader {

    private String thoughts;

    @Pointcut("execution(* com.underdogdevs.myspringaspectj." 
            + "Thinker.thinkOfSomething(String)) && args(thoughts)")
    public void thinking(String thoughts) {
    }

    @Override
    @Before("thinking(thoughts)") 
    public void interceptThoughts(String thoughts) {
        System.out.println("Intercepting volunteer's thoughts : " + thoughts);  
        this.thoughts = thoughts;
    }

    @Override
    public String getThoughts() {
        return thoughts;
    }
}

切面应该读取Volunteer的思想implements Thinker接口,使用方法thinkOfSomething(String thoughts)

public class Volunteer implements Thinker {

    private String thoughts;

    @Override
    public void thinkOfSomething(String thoughts) {
        this.thoughts = thoughts;
        System.out.println("Something");
    }

    public String getThoughts() {
        return thoughts;
    }
}

我的 java BeanConfig 带有 MagicianVolunteer

@Configuration
public class BeanConfig {

    @Bean
    public MindReader magician() {
        return new Magician();
    }

    @Bean
    public Thinker volunteer() {
        return new Volunteer();
    }  
}

我正在尝试运行它以获取Magician 方法以打印interceptThoughts 方法中的行

public class App {
    public static void main(String[] args) {
        ApplicationContext context = 
                new ClassPathXmlApplicationContext("spring-idol.xml");

        System.out.println();
        Thinker volunteer = (Thinker)context.getBean("volunteer");
        volunteer.thinkOfSomething("This is what I'm thinking");
    }
}

  • 没有错误
  • 没有例外
  • 包在@Pointcut(execution(Magician方面是正确的
  • 我的 Spring 配置 xml 中有这两项

    <context:component-scan base-package="com.underdogdevs.myspringaspectj" />
    <aop:aspectj-autoproxy />
    

问题是来自Magician 方面的@Before 没有按应有的方式打印。 我在这里遗漏了什么吗?为什么不打印?我还有其他方面的方法,它们不带参数并且运行得很好。我没有正确传递参数值吗?

【问题讨论】:

  • 这可能是一个疯狂的猜测,因为你的方面对我来说似乎是正确的;您是否尝试将 Volunteer 和 Magician 注释为 @Components ?还是将切入点放在@Before 注释内?
  • !guido 我刚试过,但它不起作用。我想这就是 this &lt;context:component-scan.../&gt; 的用途,在上下文中扫描 bean,而没有具体指定 @Component
  • 好吧,实际上context:component-scan 是用于扫描类以搜索 @Component 注释(以及@Service、@Controller,...以及@Configuration,它是元-注解@Component)

标签: java spring aop aspects


【解决方案1】:

Evgeniy 有一个解决方案,我只是想解释一下会发生什么。

当你指定时

<aop:aspectj-autoproxy />

或者用@EnableAspectJAutoProxy注释一个@Configuration类(你加载的),Spring注册一个AnnotationAwareAspectJAutoProxyCreator这是一个BeanPostProcessor

处理当前应用程序中的所有 AspectJ 注释方面 上下文,以及 Spring Advisors。任何 AspectJ 注释的类 将自动被识别,如果 Spring 应用他们的建议 AOP 的基于代理的模型能够应用它。

此过程的一个步骤包括寻找候选顾问。它通过扫描您的 bean 定义并检查 bean 类型来做到这一点。这发生在创建任何 bean 之前,因此该过程只能依赖于已声明的内容。这是猜测。

使用&lt;bean&gt; 声明,通常不会有问题,因为您会在class 属性中专门声明bean 的类。

但是,使用@Bean 方法,您可以指定一个接口。请注意,如果您使用工厂方法生成 bean,&lt;bean&gt;@Bean 声明都可能失败。

所以AnnotationAwareAspectJAutoProxyCreator 查看上下文中的所有bean 定义并猜测它们的类型。使用@Bean 声明,它会查看方法的返回类型。

在您的情况下,返回类型将是 MindReader,它不是候选类型,因为它没有 @Aspect 注释。因此,不会应用任何建议(无代理),您也不会看到预期的行为。

可能的解决方案:

  • Evgeniy's solution 更改返回类型,从而让 Spring 清楚 bean 类型是什么
  • 去掉你的@Bean定义,用@Component注释你的Magician类,并让它的包是component-scanned。因为类型显然是带注释的类,所以 Spring 将能够分辨出它也被 @Aspect 注释。

请注意,还有许多其他 BeanPostProcessor 实现会猜测 bean 的类型。您必须知道处理发生在哪个时间点(初始化之前或之后)。

【讨论】:

  • 感谢 +3 ;)
【解决方案2】:

试试这个

@Configuration
public class BeanConfig {

    @Bean
    public Magician magician() {
        return new Magician();
    }
...

我不知道它是否在 Spring 的文档中,但很明显,当 Spring 分析 magician() 的返回类型时,当它是 MindReader 时,Spring 看不到任何注释。

【讨论】:

  • 您能解释一下为什么会这样吗?是否需要使用具体类以这种方式声明所有方面 bean?