0

I'm using AspectJ with Spring to add logging to my application. I have an @Aspect class with an advice method that I want to trigger only for service methods invoked from a specific class. However, I'm having trouble constructing the correct pointcut expression to achieve this.

Here is my current code:

Aspect:

@Component
@Aspect
public class LoggingAspect {

    private final static Logger logger = LogManager.getLogger(LoggingAspect.class);

    @Pointcut("within(com.example.demo.controller.CustomerController)")
    private void withinCustomerController() {
    }

    @Pointcut("execution(* com.example.demo.service.impl.CustomerServiceImpl.*(..))")
    private void customerServiceMethods() {
    }

    @AfterReturning(pointcut = "withinCustomerController() && customerServiceMethods()", returning = "result")
    public void logServiceResult(JoinPoint joinPoint, Object result) {
        logger.info("Service method {} returned: {}", joinPoint.getSignature().getName(), result);
    }
}

Controller:

@RestController
@RequestMapping(value = "/api", produces = MediaType.APPLICATION_JSON_VALUE)
@RequiredArgsConstructor
public class CustomerController {

private final CustomerService customerService;

@PostMapping(value = "/customer")
    public KafkaMessage createCustomer(@RequestBody  RequestDto requestDto) throws IOException {
        ResponseDto responseDto = customerService.createCuistomer(requestDto);
        KafkaMessage kafkaMessage = new KafkaMessage();
        kafkaMessage.setContent("Event published");
        return kafkaMessage;
    }

}

And the Service and Implementations:

public interface CustomerService {

    ResponseDto createCustomer(RequestDto requestDto);
}
@Service
public class CustomerServiceImpl implements CustomerService {
    @Override
    ResponseDto createCustomer(RequestDto requestDto) {
        // business logic
    }
    
}

Please note that I have all the necessary dependencies added and used @EnableAspectJAutoProxy annotation. Also, the locations used in the pointcut expressions are 100% accurate (I am using Intellij Idea).If I remove the && from the pointcut in @AfterReturning, it works perfectly. Here's the working expression:

@AfterReturning(pointcut = "customerServiceMethods()", returning = "result")
    public void logServiceResult(JoinPoint joinPoint, Object result) {
        logger.info("Service method {} returned: {}", joinPoint.getSignature().getName(), result);
    }

But I need to make sure this aspect works only if the service method is invoked from the CustomerController.

Can someone help me construct the correct pointcut expression to achieve this behavior? Any suggestions or guidance would be greatly appreciated. Thank you!

  • Please follow the link to my other answer and select either of the workarounds described there, i.e. one of the native AspectJ solutions (you are currently not_ using AspectJ but Spring AOP) or Spring AOP's `ControlFlowPointcut`. Ideally, your application and aspect design should not depend on which method is called by which class, because it means tight coupling and low refactorability. You did not describe which problem you are actually trying to solve, so I cannot suggest a better alternative now. But chances are, you can change your application design to not need a control flow pointcut. – kriegaex Jun 07 '23 at 15:28

0 Answers0