How Spring AOP Creates Proxies: Inside AnnotationAwareAspectJAutoProxyCreator

This article walks through Spring’s AOP proxy creation process, detailing how enabling @EnableAspectJAutoProxy registers AnnotationAwareAspectJAutoProxyCreator, how it decides whether to wrap a bean, and the internal methods—wrapIfNecessary, isInfrastructureClass, shouldSkip, and advisor discovery—that together generate the dynamic proxies used at runtime.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
How Spring AOP Creates Proxies: Inside AnnotationAwareAspectJAutoProxyCreator

Environment

Spring Framework version 5.3.3.

1. Annotation configuration classes

@Component
@Transactional
public class PersonDAOImpl {
    @Resource
    private Dog dog;
    @Pack
    public void save(Person person) {
        System.out.println("save method invoke...");
    }
}
@Configuration
@EnableAspectJAutoProxy
@EnableTransactionManagement
public class AnnoConfig {
}

Enabling AOP registers AnnotationAwareAspectJAutoProxyCreator, a BeanPostProcessor that implements InstantiationAwareBeanPostProcessor with three key methods: postProcessBeforeInstantiation, postProcessAfterInstantiation, and postProcessProperties.

2. postProcessAfterInstantiation execution

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

This invokes wrapIfNecessary from the superclass AbstractAutoProxyCreator to decide whether the bean needs to be proxied.

wrapIfNecessary method

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors,
                new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

isInfrastructureClass

@Override
protected boolean isInfrastructureClass(Class<?> beanClass) {
    return (super.isInfrastructureClass(beanClass) ||
            (this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass)));
}

The parent implementation checks whether the class is Advice, Pointcut, Advisor, or AopInfrastructureBean. Such infrastructure classes are never proxied.

isAspect method

public boolean isAspect(Class<?> clazz) {
    return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}
private boolean hasAspectAnnotation(Class<?> clazz) {
    return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}

It returns true only for classes annotated with @Aspect and not compiled by the AspectJ compiler.

shouldSkip method

@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    for (Advisor advisor : candidateAdvisors) {
        if (advisor instanceof AspectJPointcutAdvisor &&
                ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
            return true;
        }
    }
    return super.shouldSkip(beanClass, beanName);
}

findCandidateAdvisors

protected List<Advisor> findCandidateAdvisors() {
    List<Advisor> advisors = super.findCandidateAdvisors();
    if (this.aspectJAdvisorsBuilder != null) {
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
}

The parent method retrieves all Advisor beans from the container. When AOP is enabled, a single internalTransactionAdvisor is found.

BeanFactory integration

@Override
public void setBeanFactory(BeanFactory beanFactory) {
    super.setBeanFactory(beanFactory);
    if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
        throw new IllegalArgumentException("AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
    }
    initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
}

The helper locates advisor beans, checks eligibility, and adds them to the advisor list.

Building AspectJ advisors

public List<Advisor> buildAspectJAdvisors() {
    if (aspectNames == null) {
        synchronized (this) {
            if (aspectNames == null) {
                List<Advisor> advisors = new ArrayList<>();
                aspectNames = new ArrayList<>();
                String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Object.class, true, false);
                for (String beanName : beanNames) {
                    if (!isEligibleBean(beanName)) continue;
                    Class<?> beanType = this.beanFactory.getType(beanName, false);
                    if (beanType == null) continue;
                    if (this.advisorFactory.isAspect(beanType)) {
                        // create advisors for the @Aspect bean (code omitted for brevity)
                    }
                }
                this.aspectBeanNames = aspectNames;
                return advisors;
            }
        }
    }
    return Collections.emptyList();
}

The method scans the container for beans annotated with @Aspect, creates corresponding Advisor objects for each advice method, and caches them.

Advice creation flow

For each candidate method, findAspectJAnnotationOnMethod detects an AspectJ annotation, constructs an AspectJExpressionPointcut, and then creates a concrete Advice subclass ( AspectJAroundAdvice, AspectJMethodBeforeAdvice, etc.). The advice is configured with aspect name, declaration order, and argument bindings before being added to the advisor list.

When the advisor list is non‑empty, wrapIfNecessary creates a JDK dynamic proxy or CGLIB subclass, completing the AOP proxy creation process.

Developers can extend AbstractAutoProxyCreator and override getAdvicesAndAdvisorsForBean or shouldSkip to customize proxying behavior for specific beans.

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.

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