Frage

Let me first foremention, the problem I'm facing is with the
interceptThoughts(String thoughts)
method, from the first code block, not printing

I'm running a tutorial from Spring in Action. There's a Magician class that implements MindReader interface with methods interceptThoughts(String thoughts) and 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;
    }
}

The aspect is supposed to read the mind of a Volunteer that implements Thinker interface, with method 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;
    }
}

I have my java BeanConfig with the Magician and the Volunteer

@Configuration
public class BeanConfig {

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

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

And I'm trying to run it to get the Magician method to print the line in the interceptThoughts method

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");
    }
}

  • NO Eorrrs
  • NO Exceptions
  • The package is correct in the @Pointcut(execution( in the Magician aspect
  • I have these two items in my Spring config xml

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

The problem is the @Before from the Magician aspect isn't printing as it should. Am I missing something here? Why is it not printing? I have other aspect methods that take no arguments and run just fine. Am I not passing the parameter value correctly?

War es hilfreich?

Lösung 2

try this

@Configuration
public class BeanConfig {

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

I don't know whether it is in Spring's docs, but it's clear that when Spring analizes return type of magician() and when it is MindReader Spring cannot see any annotation on it.

Andere Tipps

Evgeniy has a solution, I just want to explain what happens.

When you specify

<aop:aspectj-autoproxy />

or annotate a @Configuration class (which you load) with @EnableAspectJAutoProxy, Spring registers a AnnotationAwareAspectJAutoProxyCreator which is a BeanPostProcessor that

processes all AspectJ annotation aspects in the current application context, as well as Spring Advisors. Any AspectJ annotated classes will automatically be recognized, and their advice applied if Spring AOP's proxy-based model is capable of applying it.

One step of this process includes finding candidate Advisors. It does so by scanning your bean definitions and checking the bean types. This happens before any beans have been created and therefore the process can only rely on what has been declared. It's guessing.

With <bean> declarations, it wouldn't usually be a problem because you would specifically declare the bean's class in the class attribute.

With @Bean methods however, you can specify an interface instead. Note that <bean> and @Bean declarations could both fail if you were using a factory method to generate the bean.

So the AnnotationAwareAspectJAutoProxyCreator looks at all the bean definitions in the context and guesses their type. With a @Bean declaration, it looks at the method's return type.

In your case, the return type will be MindReader which is not a candidate since it does not have an @Aspect annotation. As such, no advice (no proxies) will be applied and you won't see the behavior you were expecting.

Possible solutions:

  • Evgeniy's solution to change the return type and therefore make it obvious to Spring what the bean type is
  • Get rid of your @Bean definition, annotate your Magician class with @Component, and have its package be component-scanned. Because the type is obviously the annotated class, Spring will be able to tell that it's also annotated with @Aspect.

Note that are many other BeanPostProcessor implementations that guess the type of the bean. You have to be aware at which point (before or after initialization) processing happens.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top