Why is my Spring AOP within pointcut not working but execution is?

Viewed 401

In my Spring Boot application I have working a pointcut against an interface that successfully works using "execution". I tried converting it to "within" as an exercise following a tutorial and it is not working and I can't figure out why.

Here is Service Interface:

package com.test.services;

import com.test.model.MyObject;

public interface MyService {
    MyObject get(Long id);
}

Here is Aspect that works:

package com.test.aop;

import org.aspectJ.lang.annoation.Aspect;
import org.aspectJ.lang.annoation.Before;
import org.aspectJ.lang.annoation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAspect {
    @Pointcut("execution(* com.test.services.MyService.*(..))")
    public void anyMyServiceMethod() {}

    @Before("anyMyServiceMethod()")
    public void beforeAnyServiceMethod() {
        System.out.println("HERE!");
    }
}

I changed it to this and it doesn't work:

package com.test.aop;

import org.aspectJ.lang.annoation.Aspect;
import org.aspectJ.lang.annoation.Before;
import org.aspectJ.lang.annoation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAspect {
    @Pointcut("within(com.test.services.*)")
    public void anyMyServiceMethod() {}

    @Before("anyMyServiceMethod()")
    public void beforeAnyServiceMethod() {
        System.out.println("HERE!");
    }
}

From what I read I thought the pointcut above using "within" should match any method in the package com.test.services but it is not. Am I missing something?

1 Answers

Probably the class implementing MyService is defined in a package other than com.test.services, such as

  • a subpackage like com.test.services.impl or
  • a totally different package like com.test.app.

As described Language semantics - Pointcuts in the AspectJ documentation,

  • some pointcut types like execution() or call() (unavailable in Spring AOP) deal with the runtime structure (match signatures),
  • while others like within() or withincode() deal with lexical structure (where the matching code is defined). See e.g. section "Program text-based pointcuts".

So if we have a class com.test.app.MyServiceImpl, you can fix your pointcut to be within(com.test.services.*+) in order to also match subtypes of classes defined in the com.test.services package. The + for subtypes is not necessary in execution(), because MyServiceImpl is also a MyService, i.e. execution(* com.test.services.MyService.*(..)) already matches.

If on the other hand the class name was com.test.services.impl.MyServiceImpl instead, the pointcut within(com.test.services..*) (double dot for including subpackages) would also work, but then it would again exclude implementations in other packages. The most universal one is within(com.test.services..*+), but which one you use really depends on your use case, and too broad is not good either in many cases.

Related