33

I have this working code for a specific package, but i want to configure it for all controllers, service and dao packages Eg

  • com.abc.xyz.content.controller
  • com.abc.xyz.content.service
  • com.abc.xyz.content.dao
  • com.abc.xyz.category.controller
  • com.abc.xyz.category.service
  • com.abc.xyz.category.dao

and so on. . . that is the base package of my project, can someone please help how I can go about doing it so that it works for all classes of my web project including controllers, thanks in advance. . .

package com.abc.xyz.utilities;

import java.util.Arrays;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect
{
    private Log log = LogFactory.getLog(this.getClass());

    @Pointcut("execution(* com.abc.xyz.content.service..*(..))")
    protected void loggingOperation()
    {
    }

    @Before("loggingOperation()")
    @Order(1)
    public void logJoinPoint(JoinPoint joinPoint)
    {
    log.info("Signature declaring type : " + joinPoint.getSignature().getDeclaringTypeName());
    log.info("Signature name : " + joinPoint.getSignature().getName());
    log.info("Arguments : " + Arrays.toString(joinPoint.getArgs()));
    log.info("Target class : " + joinPoint.getTarget().getClass().getName());
    }

    @AfterReturning(pointcut = "loggingOperation()", returning = "result")
    @Order(2)
    public void logAfter(JoinPoint joinPoint, Object result)
    {
    log.info("Exiting from Method :" + joinPoint.getSignature().getName());
    log.info("Return value :" + result);
    }

    @AfterThrowing(pointcut = "execution(* com.abc.xyz.content.service..*(..))", throwing = "e")
    @Order(3)
    public void logAfterThrowing(JoinPoint joinPoint, Throwable e)
    {
    log.error("An exception has been thrown in " + joinPoint.getSignature().getName() + "()");
    log.error("Cause :" + e.getCause());
    }

    @Around("execution(* com.abc.xyz.content.service..*(..))")
    @Order(4)
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable
    {
    log.info("The method " + joinPoint.getSignature().getName() + "() begins with " + Arrays.toString(joinPoint.getArgs()));
    try
    {
        Object result = joinPoint.proceed();
        log.info("The method " + joinPoint.getSignature().getName() + "() ends with " + result);
        return result;
    }
    catch (IllegalArgumentException e)
    {
        log.error("Illegal argument " + Arrays.toString(joinPoint.getArgs()) + " in " + joinPoint.getSignature().getName() + "()");
        throw e;
    }
    }

}
Mohan Seth
  • 761
  • 2
  • 11
  • 20

3 Answers3

70

How about one of these alternatives?

A) General execution pointcut with package restrictions:

execution(* *(..)) &&
(
    within(com.abc.xyz..controller..*) ||
    within(com.abc.xyz..service..*) ||
    within(com.abc.xyz..dao..*)
)

B) Package-restricted execution pointcuts:

execution(* com.abc.xyz..controller..*(..)) ||
execution(* com.abc.xyz..service..*(..)) ||
execution(* com.abc.xyz..dao..*(..))

I prefer B, by the way, just because it is a bit shorter and easier to read. As you have probably guessed, the .. notation means "any package or subpackage", whereas * at the end of the expression after .. means "any method in any class".

kriegaex
  • 63,017
  • 15
  • 111
  • 202
  • So basically it is possible to define all `within()` pointcut expressions using other pointcut desginators, right? I think for nested classes, `within()` can simplify the expressions (sometimes _extremely_), but otherwise it is just a convenient pointcut designator. – Behrang Jul 24 '16 at 07:53
  • 1
    Theoretically yes, but it often just does not make sense. I would always choose the (combination of) pointcut(s) most clearly expressing my intent as a developer. Good pointcuts can be read like a sentence such as: "Within packages x and y, pick all public, non-static methods in classes annotated by @Z, but only if they return values of type A." – kriegaex Jul 24 '16 at 08:39
  • Late amendment to my previous comment: `within` matches many more joinpoint types than just `execution`, e.g. `call`, `get`, `set`, `initialization`, `staticinitialization`. It also matches constructor execution which has different syntax than method execution when using `execution` pointcuts. – kriegaex Nov 11 '21 at 10:27
10

You just need to change your point cut to something like this :

@Pointcut("within(com.abc.*)")

Further reading - https://docs.spring.io/spring/docs/2.0.x/reference/aop.html

masT
  • 804
  • 4
  • 14
  • 29
Vimal Bera
  • 10,346
  • 4
  • 25
  • 47
  • 1
    Okay. For controllers you can do something like http://stackoverflow.com/questions/2011089/aspectj-pointcut-for-all-methods-of-a-class-with-specific-annotation – Vimal Bera Sep 23 '14 at 10:15
  • No mapping found for HTTP request with URI [/xyz-web-vodafone/content.showContentWorkbench.htm] in DispatcherServlet with name 'dispatcher' – Mohan Seth Sep 23 '14 at 10:27
  • firstly can I atleast configure it for services and dao packages, can U tell me how to achieve that – Mohan Seth Sep 23 '14 at 10:30
  • Its pretty simple. What you need to do is provide expression within @Pointcut itself as mentioned in answer. – Vimal Bera Sep 23 '14 at 12:06
1

Another alternative is to use

@Pointcut("bean(*Controller)")

But naming of your beans should be corresponding

ryzhman
  • 674
  • 10
  • 22