I used the custom annotation @SendMessage as the pointcut for my aspect, and since a method may send multiple messages, I set the @SendMessage annotation to Repeatable, defined @AfterReturning in my aspect class, and set this annotation twice on the methods, which have different messages.
I then noticed in my testing that the logic in the pointcut would not execute, even though the gutter icon was displayed in IDEA and I could jump between the method and the aspect.
I tried just using one @SendMessage annotation on the method and I was pleasantly surprised to find that it worked and it would execute the logic in the pointcut.
Why does Repeatable invalidate the aop? Or what causes aop to fail?
First I defined a custom annotation @SendMessage, then to make it support Repeatable I defined its container annotation @SendMessages:
// SendMessage.java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Repeatable(value = SendMessages.class)
public @interface SendMessage {
String message();
}
// SendMessages.java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SendMessages {
SendMessage[] value();
}
After that I defined the aspect class SendMessageAspect:
// SendMessageAspect.java
@Aspect
@RequiredArgsConstructor
@Component
@Slf4j
public class SendMessageAspect {
private final SendMessageService service;
@Pointcut(value = "within(com.example.service..*) && (@annotation(sendMessage))")
private void sendMessagePointcut(SendMessage sendMessage) {
}
@AfterReturning(value = "sendMessagePointcut(sendMessage)", returning = "returnValue", argNames = "jp,sendMessage,returnValue")
public void sendMessage(JoinPoint jp, SendMessage sendMessage, Object returnValue) {
// The code like this
service.sendMessage();
}
}
Finally I add the @SendMessage annotation to the method that need to use the Aspect:
// OrderServiceImpl.java
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
@SendMessage(message = "message1")
@SendMessage(message = "message2")
public Order orderSomething(String productId) {
// some code internal
return order;
}
}
I find that the orderSomeing method returns normally but doesn't execute the sendMessage method in Aspect, no error occured, in IDEA it is possible to navigate between the two classes with the gutter icon.
I tried again using only one annotation on the method, and this time it worked, executing the logic in Aspect when the method returns successfully:
// OrderServiceImpl.java
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
@SendMessage(message = "message")
public Order orderSomething(String productId) {
// some code internal
return order;
}
}
so, this is why and how to solve it? I think it's the Repeatable issue.