skip to content

What is Spring Boot's default for spring.aop.proxy-target-class, and why does it matter?

level: middleimportance: should knowfreq 55%

answer

  1. Boot default = true (since 2.0)
  2. AopAutoConfiguration applies it
  3. CGLIB everywhere -> inject by class works
  4. false = JDK-when-interfaces again
  5. then inject by interface

basics

~20 s

Spring Boot defaults spring.aop.proxy-target-class to true, so it uses CGLIB (runtime subclass) proxies for all beans, even those with interfaces. This means you can inject beans by their concrete class. Set the property to false to get JDK interface proxies again.

solid answer

~40 s

Since Spring Boot 2.0, AopAutoConfiguration sets spring.aop.proxy-target-class=true by default. So a Boot app uses CGLIB class-based proxies everywhere, even for beans implementing interfaces — unlike plain Spring, which would pick JDK dynamic proxies when interfaces exist. This matters because CGLIB proxies are subclasses of the target, so injecting or looking up a bean by its concrete class works, avoiding a whole class of 'BeanNotOfRequiredTypeException'/'no bean of type Impl' surprises. It applies uniformly to @Transactional, @Cacheable, and custom aspects. The trade-off is CGLIB's constraints (no final classes/methods). To revert to interface-based JDK proxying app-wide, set spring.aop.proxy-target-class=false in application.properties; then you must inject beans by their interface type.

go deeper

for a junior

Know Boot defaults the property to true so CGLIB is used everywhere.

for a middle

Explain the difference from plain Spring and the inject-by-class consequence.

for a senior

Diagnose autowiring failures caused by flipping the property to false.

for a principal

Decide the org-wide convention and document injection-by-interface discipline if disabling it.

## The property `spring.aop.proxy-target-class` is Spring Boot's single global switch for AOP proxy strategy. It flows into `AopAutoConfiguration`, which registers the auto-proxy creator and calls `setProxyTargetClass(...)` accordingly. **Boot's default is `true`** (established in Spring Boot 2.0; earlier versions defaulted to JDK-when-interfaces). ## What 'true' means at runtime - Every AOP-proxied bean is wrapped by a **CGLIB subclass**, regardless of whether it implements interfaces. - The proxy `instanceof TargetClass` is true, so `@Autowired OrderServiceImpl` resolves. - This is the opposite of plain-framework Spring, where an interface-implementing bean would get a **JDK dynamic proxy** that is only assignable to the interface. ## Why Boot chose this default - **Fewer footguns.** Newcomers frequently inject by concrete class or by a type not on the interface; with JDK proxies those injections fail confusingly. CGLIB avoids it. - **Consistency.** One proxy technology across `@Transactional`, `@Cacheable`, `@Async`, and custom `@Aspect`. - **Public methods not on any interface** still get advised. ## How to override In `application.properties`/`application.yml`: ``` spring.aop.proxy-target-class=false ``` Now Boot uses JDK proxies whenever a bean implements at least one interface (falling back to CGLIB only for no-interface beans). After flipping it, **inject beans by their interface**, not the impl class, or startup wiring breaks. ## Precedence note Per-annotation `proxyTargetClass` settings and the property interact; in a Boot app the property is the effective global default. If you set `@EnableAspectJAutoProxy(proxyTargetClass=false)` but leave the Boot property true, behavior can be surprising — prefer configuring the single property. ## Costs to remember - CGLIB cannot proxy `final` classes or override `final`/`private`/`static` methods — advice silently skips them. - Uses Objenesis to instantiate without invoking constructors normally; be careful with constructor logic. ## When to use Keep the default (true) for typical apps. Switch to false only if your architecture depends on interface-only proxies — e.g. you want beans to be strictly programmed-to-interface and easily mockable, and you have `final` classes you cannot subclass.

  • You set spring.aop.proxy-target-class=false and now startup fails to autowire OrderServiceImpl. Why?
    With interfaces present, Spring now creates a JDK dynamic proxy that only implements OrderService, not the concrete OrderServiceImpl type, so injection by the impl class no longer matches. Inject the interface instead.

saying these in an interview costs you the question

  • Saying Boot defaults to JDK proxies
  • Claiming the property has no global effect in Boot
  • Believing setting it false lets you still inject by impl class
  • Confusing this with disabling AOP entirely

context