skip to content

What is a CGLIB proxy in Spring, and how does it differ from a JDK dynamic proxy?

level: juniorimportance: must knowfreq 70%

answer

  1. runtime subclass overrides methods
  2. no interface needed
  3. org.springframework.cglib repackaged
  4. JDK proxy = interfaces, CGLIB = subclass
  5. Boot default proxyTargetClass=true

basics

~10 s

A CGLIB proxy is a runtime-generated subclass of your target class that overrides its methods to add behavior like transactions. Unlike a JDK dynamic proxy, it doesn't need the class to implement an interface.

solid answer

~40 s

Spring creates proxies to wrap beans with cross-cutting behavior (AOP advice, @Transactional, @Async, @Cacheable). There are two mechanisms. A JDK dynamic proxy implements the target's interfaces and requires at least one interface. A CGLIB proxy generates a runtime subclass of the concrete target class, overriding each non-final method to route calls through the interceptor chain. Because CGLIB subclasses, it works on classes with no interfaces. Spring ships a repackaged copy of the library under org.springframework.cglib so there's no external dependency. Spring Boot defaults to CGLIB (proxyTargetClass=true) even when interfaces exist, for consistency. The key limitation: since it subclasses, final classes can't be proxied and final, private, or static methods can't be overridden, so advice on those is silently skipped.

code

java · 12 lines
java
// No interface — Spring must use a CGLIB subclass proxy to advise @Transactional
@Service
public class PaymentService {

    @Transactional
    public void charge(long accountId, Money amount) {
        // proxy opens a tx before this body runs, commits/rolls back after
    }
}

// The bean Spring injects is actually a runtime-generated subclass:
//   class PaymentService$$SpringCGLIB$$0 extends PaymentService { ... }

go deeper

for a junior

Know CGLIB = runtime subclass, works without interfaces, adds behavior like @Transactional.

for a middle

Contrast JDK proxy (interface) vs CGLIB (subclass) and know Boot defaults to CGLIB.

for a senior

Explain the interceptor override mechanism and repackaged org.springframework.cglib.

for a principal

Discuss proxy-strategy tradeoffs, uniform CGLIB default rationale, and design implications for API surfaces.

**What a proxy is.** A proxy is a stand-in object that looks like your bean but wraps each method call with extra behavior (an "interceptor chain"). Spring uses proxies to implement AOP aspects and annotations such as `@Transactional`, `@Async`, `@Cacheable`, and `@Retryable`. When you call a method on the injected bean, you're actually calling the proxy, which runs the advice (e.g. open a transaction) and then delegates to your real code. **Two proxy strategies in Spring.** 1. **JDK dynamic proxy** — built into the JDK via `java.lang.reflect.Proxy`. It creates an object that *implements the same interfaces* as the target. It requires the bean to implement at least one interface, and only methods declared on those interfaces can be advised. The proxy holds a reference to the target and is a *separate* object from it. 2. **CGLIB proxy** — CGLIB (Code Generation Library) generates a brand-new class at runtime that *extends* (subclasses) your concrete target class. Spring bundles a repackaged copy of CGLIB under `org.springframework.cglib.*` (relocated from the original `net.sf.cglib`), so you don't add a dependency yourself. The generated subclass overrides every non-final, non-private method and inserts a `MethodInterceptor` call, which runs the advice chain and then invokes the original method body via the superclass. **Why CGLIB exists.** Not every bean implements an interface. Plenty of `@Service` / `@Component` classes are plain concrete classes. JDK proxies can't wrap those, so CGLIB subclassing fills the gap. **How Spring chooses.** Historically Spring used JDK proxies when the target implemented interfaces and CGLIB otherwise. You can force CGLIB with `proxyTargetClass = true` (on `@EnableAspectJAutoProxy`, `@EnableTransactionManagement`, etc.). **Spring Boot sets `proxyTargetClass = true` by default**, so Boot apps use CGLIB even for interface-bearing beans — this avoids surprises where injecting the concrete type fails. **Core limitations (because it subclasses):** - A `final` class cannot be subclassed → cannot be proxied by CGLIB. - `final` methods cannot be overridden → advice on them is silently skipped. - `private` methods aren't inherited/overridable → not advised. - `static` methods belong to the class, not instances → not proxied. **Gotcha — self-invocation.** Advice only fires when a call goes *through the proxy*. If a method calls another advised method on `this`, the call bypasses the proxy (it's a plain `super`-level call within the same object), so the second method's advice does not run. This is true for both proxy types. **When to use.** Prefer JDK proxies when you code to interfaces (cleaner, no subclassing constraints); use CGLIB when there's no interface, or use Boot's CGLIB default for uniform behavior. Avoid `final` on classes/methods you intend to advise.

  • If a class implements an interface, which proxy does Spring use?
    By default plain Spring uses a JDK dynamic proxy; but Spring Boot sets proxyTargetClass=true, so Boot uses CGLIB even then. You can also force CGLIB explicitly via proxyTargetClass.
  • Where does the CGLIB code come from — do you add a dependency?
    No. Spring repackages CGLIB inside spring-core under org.springframework.cglib, so it's always available without a separate artifact.

saying these in an interview costs you the question

  • Saying CGLIB requires the class to implement an interface (that's JDK proxies)
  • Claiming CGLIB modifies/rewrites the original class bytecode (it generates a new subclass)
  • Thinking you must add a cglib Maven dependency manually

context