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.
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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
