Why Your Custom Spring AOP Advisor Isn’t Triggered and How to Fix It

This article explains the behavior of Spring Boot’s @Configuration and @Import annotations, the reasons a custom PointcutAdvisor may not be applied when using JDK proxies, and provides two solutions—adding the @DS annotation to interface methods or forcing CGLIB proxying with proxyTargetClass=true—to ensure the advice executes correctly.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Why Your Custom Spring AOP Advisor Isn’t Triggered and How to Fix It

Environment: Spring Boot 2.3.10.

1. @Configuration annotation

The annotation has a proxyBeanMethods attribute defaulting to true. When true, all @Bean -annotated methods are CGLIB‑proxied, allowing direct calls within the class or external classes to return the same shared bean instance.

2. @Import annotation

Using @Import registers the specified class, e.g. @Import({RWImportSelector.class}). The selector can implement ImportSelector and EnvironmentAware to conditionally import configuration based on properties.

public class RWImportSelector implements ImportSelector, EnvironmentAware {
    private static final String RW_CONFIG_ENABLED = "rw.config.enabled";
    private static final Boolean RW_CONFIG_ENABLED_DEFAULE = Boolean.TRUE;
    private Environment env;
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // ... logic omitted for brevity
    }
    @Override
    public void setEnvironment(Environment environment) {
        this.env = environment;
    }
}

ImportSelector can implement corresponding *Aware interfaces.

The classes returned by selectImports also respect @ConditionalOn* annotations such as @ConditionalOnProperty.

3. Custom Advisor not taking effect

The requirement is to intercept every method annotated with @DS. A custom PointcutAdvisor is defined, but the advice is never invoked because Spring creates a JDK dynamic proxy for beans that implement an interface. The proxy’s Method object points to the interface method, which lacks the @DS annotation, so the pointcut does not match.

@Component
public class CustomAdvisor implements PointcutAdvisor {
    @Override
    public Advice getAdvice() {
        return new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("I am called...");
                return invocation.proceed();
            }
        };
    }
    @Override
    public boolean isPerInstance() { return true; }
    @Override
    public Pointcut getPointcut() {
        return new Pointcut() {
            @Override
            public MethodMatcher getMethodMatcher() {
                return new MethodMatcher() {
                    @Override
                    public boolean matches(Method method, Class<?> targetClass, Object... args) {
                        return false;
                    }
                    @Override
                    public boolean matches(Method method, Class<?> targetClass) {
                        return method.isAnnotationPresent(DS.class);
                    }
                    @Override
                    public boolean isRuntime() { return false; }
                };
            }
            @Override
            public ClassFilter getClassFilter() { return ClassFilter.TRUE; }
        };
    }
}

When the bean implements an interface, Spring uses JdkDynamicAopProxy. The core line that retrieves the interceptor chain is:

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

If the chain is empty, the original method is invoked directly, which is why only the System.out.println inside update() appears.

4. How to solve

Two approaches:

Add @DS on the interface method.

Force CGLIB proxying by enabling proxyTargetClass=true in @EnableAspectJAutoProxy:

@EnableAspectJAutoProxy(proxyTargetClass = true)

The proxyTargetClass flag is processed in AspectJAutoProxyRegistrar, which registers AnnotationAwareAspectJAutoProxyCreator and, if the flag is true, forces the auto‑proxy creator to use class‑based (CGLIB) proxies.

5. Introduction advice example

Introduction advice allows a class that does not implement an interface to gain that interface’s behavior without modifying its source.

@Component
public class Apple {
    public void color() { System.out.println("red color..."); }
}
public interface FruitDAO { void eat(); }
public class CustomIntroductionInterceptor implements IntroductionInterceptor, FruitDAO {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        if (implementsInterface(invocation.getMethod().getDeclaringClass())) {
            System.out.println("I am Introduction enhancement...");
            return invocation.getMethod().invoke(this, invocation.getArguments());
        }
        return invocation.proceed();
    }
    @Override
    public boolean implementsInterface(Class<?> intf) {
        return FruitDAO.class.isAssignableFrom(intf);
    }
    @Override
    public void eat() { System.out.println("This is a qualified fruit"); }
}
public class IntroductionAopProxy extends AbstractAutoProxyCreator {
    @Override
    protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource customTargetSource) {
        return new Object[] { new DefaultIntroductionAdvisor(new CustomIntroductionInterceptor(), FruitDAO.class) };
    }
    @Override
    protected boolean shouldSkip(Class<?> beanClass, String beanName) {
        return !Apple.class.isAssignableFrom(beanClass);
    }
}

The proxy only applies to Apple, granting it the FruitDAO capability.

… (article continues)

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

aopSpring BootannotationscglibJDK ProxyCustom Advisor
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.