1

I find the same question in there but didn`t find a useful answer, so I support more details. My code is the following.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DS {
    String value();
}

public class AnnotationAspect {
    @Around("@target(com.yh.application.DS)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        String dsName = getDataSourceAnnotation(joinPoint).value();
        System.out.println("enter in aspect:" + dsName);
        return joinPoint.proceed();
    }

here is a demo, just run the application you can see the error stack trace

Unable to proxy interface-implementing method
 [public final void org.springframework.boot.web.servlet.RegistrationBean.onStartup
 (javax.servlet.ServletContext) throws javax.servlet.ServletException] 
 because it is marked as final: Consider using interface-based JDK proxies instead!

seems I need to change the aop proxy type to JDK, but when I did this, another error is prompted.

The bean 'dispatcherServlet' could not be injected as a 'org.springframework.web.servlet.DispatcherServlet' because it is a JDK dynamic proxy 

Does anyone help me? thank you!

nectar
  • 11
  • 1
  • That isn't an error or stacktrace it is an warning message. – M. Deinum Dec 08 '20 at 14:35
  • The answer to the question you shared has hints (3rd point) to limit the scope of the pointcut . Try the same and verify the issue goes off. – R.G Dec 08 '20 at 15:05
  • 2
    @nectar a pointcut like the following would limit the scope to the beans within the base package `com.yh` Pointcut expression : `@Around("@target(com.yh.application.DS) && within(com.yh..*)")` – R.G Dec 09 '20 at 03:03
  • Feedback, please. Thank you. – kriegaex Dec 13 '20 at 03:03
  • @R.G why is that happening? I am seeing behavior where @ target is used to annotate class level, and @ annotation on method level - this is when aspects work. Any idea why this is happening? I am confused? – alext Nov 11 '22 at 19:02
  • @sem10 without seeing the code it is not possible to identify the exact cause. w.r.t my comment , when the scope of a pointcut is global , every bean has to be adviced . This means , with Spring AOP , every bean is attempted to be proxied , which will not work for a `final` class as in the question. – R.G Nov 12 '22 at 04:46

1 Answers1

1

R.G's solution is correct, you ought to limit the pointcut scope. BTW, looking at your aspect code, I noticed this contrived way of getting the annotation value:

  private DS getDataSourceAnnotation(ProceedingJoinPoint joinPoint) {
    Class<?> targetClass = joinPoint.getTarget().getClass();
    DS dsAnnotation = targetClass.getAnnotation(DS.class);
    if (Objects.nonNull(dsAnnotation)) {
      return dsAnnotation;
    }
    else {
      MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
      return methodSignature.getMethod().getAnnotation(DS.class);
    }
  }

I suggest you just bind the annotation to an advice method parameter like this:

package com.yh.application;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class AnnotationAspect {
  @Before("@target(ds) && within(com.yh..*)")
  public void interceptDS(JoinPoint joinPoint, DS ds) {
    System.out.println(joinPoint + " -> DS value = " + ds.value());
  }
}

Update:

I forgot to explain why you were getting the error in the first place: Pointcuts like this(), target(), @this(), @target() can only be determined dynamically during runtime because they access active object instances. Hence, all possible Spring components (also internal ones) are being aspect-woven, which is also the reason why the workaround to limit the aspect scope by using statically evaluated pointcut designators like within() help you avoid the problem.

But actually, using a statically evaluated pointcut designator in the first place, if it is a viable alternative, is the best idea. It is also faster than weaving the world, creating dozens or hundreds of proxies, and then to dynamically evaluate pointcuts over and over again. Luckily, in this case such an alternative exists: @within().

@Aspect
@Component
public class AnnotationAspect {
  @Before("@within(ds)")
  public void interceptDS(JoinPoint joinPoint, DS ds) {
    System.out.println(joinPoint + " -> DS value = " + ds.value());
  }
}
kriegaex
  • 63,017
  • 15
  • 111
  • 202