-1

Let's say I need to enhance the shower() method with a @MusicAround advice to give me some music before and after executing the shower() method.

public class Me {
    @MusicAround
    public void shower() {
        // shower code omitted
    }
}

First I created the new annotation @MusicAround.

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MusicAround {

Then bind it with an aspect MusicAspect.

@Aspect
public class MusicAspect {
    @Around("@annotation(MusicAround)")
    public Object musicAround(ProceedingJoinPoint joinPoint) throws Throwable {
        IPhone iphone = new IPhone();
        Iphone.music();
        joinPoint.proceed();
        iphone.music();
    }
}

Configure MusicAspect as a Bean. @EnableAspectJAutoProxy annotation leaves spring to encapsulate the aspect proxy for me.

@Configuration
@EnableAspectJAutoProxy
public class ApplicationConfig {
    // ... other beans omitted

    @Bean 
    public MusicAspect musicAspect() {
        return new MusicAspect();
    }
}

In main method, get Me instance from context, and execute shower() method.

public static void main(String[] args) {
    try {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
        Me me = context.getBean(Me.class);
        me.shower();
        context.close();
    } catch (ApplicationContextException ace) {
        // handle exception
    }
}

Now I can enjoin the music during the shower.

<hey jude>
I'm showering
<don't be so serious>

The problem is that in this way MusicAspect class is coupled with IPhone class. I want to decouple them by injecting IPhone object as a parameter as below,

@Aspect
public class MusicAspect {
    @Around("@annotation(MusicAround)")
    public Object musicAround(ProceedingJoinPoint joinPoint, IPhone iphone) throws Throwable {
        iphone.music();
        joinPoint.proceed();
        iphone.music();
    }
}

Of cause a second parameter "iphone" in musicAround() method will not be allowed here. Is there any spring features that I can use to decouple IPhone and MusicAspect in this case?

!Note: thanks @kriegaex for the proofreading.

shen
  • 933
  • 10
  • 19
  • 1
    This question suffers from the [XY problem](https://meta.stackexchange.com/a/66378/309898): It explains **how** you technically dream up to achieve your goal instead of explaining **what** you actually want to achieve. The sample code is unsuitable for explaining your objective, and so is your explanation of same. An annotation is just an annotation, it does nothing. The aspect does something. What would you achieve by "injecting" something into an annotation, whatever that may mean? Please edit and improve your question. Thank you. – kriegaex May 02 '21 at 05:52
  • @kriegaex now looks better? – shen May 02 '21 at 06:47
  • 1
    https://stackoverflow.com/questions/9633840/spring-autowired-bean-for-aspect-aspect-is-null – k-wasilewski May 02 '21 at 07:32
  • thanks @k-wasilewski `@Autowired` tag solved my problem. – shen May 02 '21 at 18:24

2 Answers2

0

This is a preliminary answer, because the content is not suitable for a comment.

When looking at the code in your updated question, some things strike me as strange:

  • I wonder why everyone is so eager to always use aspects in combination with annotations. Why not use a pointcut which directly targets packages, classes or methods of interest? All this annotation pollution is horrible, if not absolutely necessary. Ideally, the application code should be completely agnostic of the existence of aspects.
  • You use the @annotation pointcut designator incorrectly. Instead of @annotation(@MusicAround) it should be @annotation(MusicAround). But also that only works if the annotation happens to be in the exact same package as the aspect, otherwise you need @annotation(fully.qualified.package.name.MusicAround).
  • You use a MusicAspect, but then declare a MinstrelAroundAdvice bean. That does not seem to match. Besides, an aspect is an aspect, the method inside it which actually does something is the advice. So the class name *Advice for an aspect is simply wrong. Better use *Aspect instead or something else which properly describes what the aspect does. In this case, MusicAspect seems just fine to me.

Now concerning your actual question, it is still unclear to me. Is it about how to inject (auto-wire) another bean into an aspect instance?

Of course I was not allowed to do so.

Why "of course"? What was not allowed? How did you notice? Did something not work? Did you get an error message? A stack trace? Please explain clearly what you tried, what the expected result is and what happened instead. Make your problem reproducible. Your code snippets do not do that, unfortunately. Just imagine for a minute that someone else would ask you the same question without you seeing the full code and without other context information necessary to understand the problem. Could you answer it? If your helpers do not understand the problem, how can they answer your question? Please be advised to learn what an MCVE is.

kriegaex
  • 63,017
  • 15
  • 111
  • 202
  • Pointcut expression is not flexible and hard to use. Adding annotation wherever we want looks more intuitive. Pollution? You think a long pointcut expression like `@Pointcut("execution(public String com.baeldung.pointcutadvice.dao.FooDao.findById(Long))")` is beautiful? – shen May 02 '21 at 19:24
  • It is not hard to use and it is flexible, because you can change it. More importantly, you can use and maintain it in a **single place**, without changing your application code in potentially hundreds of places. Users can forget adding annotations, but an aspect maintainer can make sure the aspect targets the right places. Anyway, I just mentioned that because it is over-engineering in your beginner's example. The actual problem was the syntax error in your pointcut and the fact that you did't know how to auto-wire a component - the latter being Spring basics, not AOP-related at all. – kriegaex May 03 '21 at 03:19
0

Problem solved with the help of @k-wasilewski and @kriegaex. Thanks bro.

The answer is @Autowired annotation.

Define IPhone as a field of MusicAspect class. Add @Autowired tag, which tells spring context to initialize the IPhone instance for us.

@Aspect
public class MusicAspect {

    @Autowired
    private IPhone iphone;

    @Around("@annotation(MusicAround)")
    public Object musicAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Iphone.music();
        joinPoint.proceed();
        iphone.music();
    }

}

Don't forget to register IPhone bean in ApplicationConfig. The rest part remain the same.

@Configuration
@EnableAspectJAutoProxy
public class ApplicationConfig {
    // ... other beans omitted

    @Bean 
    public IPhone iphone() {
        return new IPhone();
    }
}

The code passed unit-test on my laptop.

shen
  • 933
  • 10
  • 19