Backend Development 10 min read

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.

<code>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;
    }
}
</code>

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.

<code>@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; }
        };
    }
}
</code>

When the bean implements an interface, Spring uses

JdkDynamicAopProxy

. The core line that retrieves the interceptor chain is:

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

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

:

<code>@EnableAspectJAutoProxy(proxyTargetClass = true)
</code>

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.

<code>@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);
    }
}
</code>

The proxy only applies to

Apple

, granting it the

FruitDAO

capability.

… (article continues)

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

login 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.