0

I have created my custom annotation:

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Condition {
    String value();
}

I want to use this annotation to determine whether or not to run advice, my try:

@Condition("some.config")
@Around("execution(public * someMethod())")
Object doSomething(ProceedingJoinPoint joinPoint) throws Throwable {
    // some logic here
}

@Around("@annotation(condition)")
Object checkCondition(ProceedingJoinPoint joinPoint, Condition condition) throws Throwable {
    String property = (String) configuration.getProperty(condition.value());
    if (Boolean.valueOf(property)){
        return joinPoint.proceed();
    } else {
        return null;
    }
}

It works when I use @Condition on some other methods, i.e. the checkCondition is applied and then the method is executed or not based on config value. For advice doSomething it doesn't get applied though.

qwerty1423
  • 295
  • 5
  • 17
  • What do you mean "doesn't work for advice"? Share [mcve] code. – M. Prokhorov Feb 15 '18 at 12:06
  • I've updated the question to clarify. – qwerty1423 Feb 15 '18 at 12:43
  • Why would it be expected to be applied if that's your custom annotation, and nothing apart from your own code knows about it? – M. Prokhorov Feb 15 '18 at 12:54
  • Maybe because this is all my own code? Why are you so aggressive? I'm just new to spring-aop and trying to mess around with it a little bit. – qwerty1423 Feb 15 '18 at 13:30
  • Agressive or not, *why do you think that your own custom annotation would make any difference to the code that knows nothing about it, without you writing the code?*. Spring AOP advices are also not Spring components themselves, and are not considered for wiring. It may also work like that for aspectJ in general, otherwise pointcuts that are just a little too general would go in infinite loops. – M. Prokhorov Feb 15 '18 at 13:57

1 Answers1

1

You said your aspect works for other components, just not the aspect itself. From this statement I gather that

  1. your aspect is wired correctly (e.g. annotated with @Component and detected by component scan or wired manually via XML config) and
  2. you use proxy-based Spring AOP.

In (2) is the source of your problem. According to the Spring manual aspects themselves are exempt from being aspect targets themselves:

Advising aspects with other aspects?

In Spring AOP, it is not possible to have aspects themselves be the target of advice from other aspects. The @Aspect annotation on a class marks it as an aspect, and hence excludes it from auto-proxying.

So M. Prokhorov is somewhat wrong when saying that aspects are not (or cannot be) Spring components, but he is right insofar as by design you cannot self-advise an aspect or advise other aspects. His assumption that it may work with AspectJ is also correct. It does work with AspectJ, so if you need it to you can configure Spring to use AspectJ via LTW instead of Spring AOP for this case.

kriegaex
  • 63,017
  • 15
  • 111
  • 202
  • Since the initial goal was simply to enable or disable aspects based on some configuration property, then [this question and answer](https://stackoverflow.com/questions/29406192/can-we-enable-or-disable-aspect-based-on-value-of-any-flag-or-through-configurat) is also quite helpful. – M. Prokhorov Feb 15 '18 at 15:05
  • 1
    Yes, for Spring AOP the solution based on `@ConditionalOnExpression` seems to be a nice way to achieve that. I am not a Spring user, though, so usually I am looking for Spring-independent solutions. If it is really just about en-/disabling an aspect based on a condition, a few years ago I showed how to do that [dynamically via JMX](https://stackoverflow.com/a/24017288/1082681). The used `if()` pointcut from AspectJ is not available in Spring AOP. It could be replaced by an `if` expression directly in the code if a switch to AspectJ is not desired. – kriegaex Feb 15 '18 at 16:12