4

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

我正在运行Spring in Action的教程。有一个Magicianimplements 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;
    }
}

我有我的javaBeanConfigMagicianVolunteer

@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 />
    

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

4

2 回答 2

2

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

当您指定

<aop:aspectj-autoproxy />

或用 注释一个@Configuration类(你加载的),@EnableAspectJAutoProxySpring 注册AnnotationAwareAspectJAutoProxyCreator一个BeanPostProcessor

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

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

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

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

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

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

可能的解决方案:

  • Evgeniy更改返回类型的解决方案,因此让 Spring 清楚 bean 类型是什么
  • 摆脱你的@Bean定义,用 注释你的Magician@Component,并让它的包被component-scanned。因为类型显然是带注释的类,所以 Spring 将能够分辨出它也被注释了@Aspect

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

于 2014-01-20T21:21:53.900 回答
1

尝试这个

@Configuration
public class BeanConfig {

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

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

于 2014-01-18T08:03:11.903 回答