skip to content

In Spring Boot, how is aspect auto-proxying enabled, and how does it differ from a plain Spring app?

level: middleimportance: should knowfreq 45%

answer

  1. Boot: AopAutoConfiguration
  2. Trigger = aspectjweaver on classpath
  3. spring.aop.auto (default true)
  4. Boot default proxy-target-class=true -> CGLIB
  5. Plain Spring must add @EnableAspectJAutoProxy

basics

~10 s

Spring Boot enables it automatically via AopAutoConfiguration when aspectjweaver is on the classpath, so you normally don't add @EnableAspectJAutoProxy. In a plain Spring app you must add the annotation yourself.

solid answer

~30 s

In plain Spring you must put @EnableAspectJAutoProxy on a @Configuration class to register the auto-proxy creator. In Spring Boot, AopAutoConfiguration does this for you: it's active when the aspectjweaver dependency (typically via spring-boot-starter-aop) is present, gated by @ConditionalOnProperty spring.aop.auto (default true). A subtle difference is the proxy strategy: Boot sets spring.aop.proxy-target-class=true by default, so it uses CGLIB (class-based) proxies even for beans with interfaces, whereas plain @EnableAspectJAutoProxy defaults proxyTargetClass=false (JDK proxy when interfaces exist). You can still add @EnableAspectJAutoProxy explicitly in Boot to force settings, or set spring.aop.proxy-target-class / spring.aop.auto in properties. Both paths ultimately register the same AnnotationAwareAspectJAutoProxyCreator.

code

properties · 4 lines
properties
# Spring Boot toggles (defaults shown as comments)
# spring.aop.auto=true               # master switch for aspect auto-proxying
spring.aop.proxy-target-class=false  # force JDK proxies when a bean has interfaces
#                                    # (Boot's default is true -> CGLIB)

go deeper

for a junior

Know Boot enables it automatically; you rarely add the annotation.

for a middle

Name AopAutoConfiguration, the classpath trigger, and the two spring.aop.* properties.

for a senior

Explain Boot's CGLIB default and why, plus how to override.

for a principal

Discuss implications for @Transactional/@Cacheable, class- vs interface-injection pitfalls, and startup conditions.

## Two ways the auto-proxy creator gets registered ### Plain Spring (no Boot) You opt in explicitly: ```java @Configuration @EnableAspectJAutoProxy public class AopConfig {} ``` The annotation imports `AspectJAutoProxyRegistrar`, registering `AnnotationAwareAspectJAutoProxyCreator`. Without it, `@Aspect` beans are inert. ### Spring Boot (auto-configuration) Boot ships `org.springframework.boot.autoconfigure.aop.AopAutoConfiguration`. Simplified, it looks like: ```java @AutoConfiguration @ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true) public class AopAutoConfiguration { @Configuration @ConditionalOnClass(Advice.class) // aspectjweaver on classpath @EnableAspectJAutoProxy(proxyTargetClass = false) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false") static class JdkDynamicAutoProxyConfiguration {} @Configuration @ConditionalOnMissingClass("org.aspectj.weaver.Advice") @EnableAspectJAutoProxy(proxyTargetClass = true) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true) static class ClassProxyingConfiguration {} } ``` Key points: - **`spring.aop.auto`** (default `true`) — master switch; set to `false` to disable entirely. - **`spring.aop.proxy-target-class`** — Boot's global default is **`true`** (set in `SpringApplication`/Boot's defaults), so Boot uses **CGLIB** proxies even when a bean implements interfaces. This is the notable behavioral difference from a bare `@EnableAspectJAutoProxy`, whose `proxyTargetClass` defaults to `false`. - Trigger: presence of `aspectjweaver` (usually via `spring-boot-starter-aop`). ### Why Boot prefers CGLIB Defaulting to class proxies avoids a common surprise: injecting a bean by its concrete class rather than its interface fails with a JDK proxy (the proxy is not an instance of the concrete class). CGLIB proxies subclass the target, so both interface- and class-typed injection work. This also matters for `@Transactional`/`@Cacheable`, which use the same proxy infrastructure. ### Overriding in Boot - `spring.aop.proxy-target-class=false` → JDK proxies when interfaces exist. - `spring.aop.auto=false` → no auto-proxying at all. - Or add your own `@EnableAspectJAutoProxy(...)` — an explicit user config wins. ### Same end result Both routes register the identical `AnnotationAwareAspectJAutoProxyCreator`; auto-config is just conditional convenience.

  • Why does Spring Boot default to CGLIB (proxy-target-class=true) rather than JDK proxies?
    To avoid injection failures: with a JDK proxy the bean is only assignable to its interfaces, so autowiring by concrete class fails. CGLIB subclasses the target, so both interface and class injection work — safer default for @Transactional/@Cacheable too.

saying these in an interview costs you the question

  • Saying you must always write @EnableAspectJAutoProxy in Boot
  • Claiming Boot defaults to JDK dynamic proxies
  • Not knowing spring.aop.auto / spring.aop.proxy-target-class exist
  • Thinking Boot uses a different proxy creator than plain Spring

context