Spring Boot: Interfaces or CGLIB?

Updated: 2025-06-21

Interfaces vs CGLIB

Interfaces or not? This discussion came up regularly in many Java projects using Spring Boot.

More 'conservative' developers preferred to use interfaces 'to have a better design / architecture'.
For more 'modernist' developers add interfaces for a single implementation is a useless boilerplate.

I was mostly in the second field until when I decided to look in the detail of what Spring is doing.

It’s more than just design: Why Interfaces matter in Spring

In its early implementations, Spring heavily relied on interfaces. The advantage of using interfaces was that Spring
could easily proxy them adding features with AOP.

The development trend moved from Interfaces everywhere (J2EE memories) to a more minimalistic approach.

To change the behavior of a class and add features without Interfaces, Spring is
using CGLIB.

CGLIB can modify the behavior of a class at runtime. Unlike interface-based proxies, CGLIB works by creating a subclass.

What Spring recommends?

As it is good practice to program to interfaces rather than classes, business classes normally implement one or more business interfaces

You can find this sentence in the official documentation, and it doesn't leave space to many interpretations :)

Spring recommends using interfaces for good design, but it helps us developers if we choose a different strategy.

Spring Boot and Interfaces, JDK Dynamic Proxy

Using a standard Interface, Spring Boot uses the JDK Dynamic Proxy: java.lang.reflect.Proxy that comes with the JDK.

          ┌────────────────────┐ 
          │ OrderService       │ 
          │ (Interface)        │ 
          └────────┬───────────┘ 
                   │ 
                   ▼ 
          ┌────────────────────┐ 
          │ OrderServiceImpl   │ 
          └────────┬───────────┘ 
                   │ 
                   ▼ 
       ┌────────────────────────────┐ 
       │ JDK Proxy implements       │ 
       │ OrderService               │ 
       └────────┬───────────────────┘ 
                │ (delegates to impl) 
                ▼ 
     ┌──────────────────────────────┐ 
     │  @Transactional logic        │ 
     │  starts transaction          │ 
     │  calls OrderServiceImpl      │ 
     │  commits or rollbacks TX     │ 
     └──────────────────────────────┘ 

When we debug a service that uses an interface it's easy to see the content of the object:

Interface Debug

Spring Boot without Interfaces, CGLIB

When we don't declare an interface and we annotate a class as service Spring will use CGLIB to subclass the Service.

          ┌────────────────────┐ 
          │  OrderService      │ 
          │  (No interface)    │ 
          └────────┬───────────┘ 
                   │ 
                   ▼ 
       ┌───────────────────────────┐ 
       │ CGLIB Subclass Proxy      │ 
       │ OrderService$$EnhancerBy~ │ 
       └────────┬──────────────────┘ 
                │ (overrides methods) 
                ▼ 
     ┌──────────────────────────────┐ 
     │  @Transactional logic        │ 
     │  starts transaction          │ 
     │  calls super.method()        │ 
     │  commits or rollbacks TX     │ 
     └──────────────────────────────┘ 

This is what you see if you debug this service. The content is confusing and it's not very helpful. In my opinion is were the interfaces have a real value for the developer.

CGLIB Debug

Advantages of the two strategies

I think the biggest advantages of CGLIB is the faster inital development, less code, less boilerplate.
It's ideal for prototyping and small projects.

JDK Proxies (Interfaces) are more robust for large and complex codebases, indipendently from the number of the number of
implementations of the interfaces.

AspectCGLIBJDK Proxy
Requires InterfacesNoYes
Works with finalNoNo
Debuggable clean class namesNoYes
Memory usageHeavier (Subclasses bytecode uses Metaspace)Lighter
Startup timeSlower (Subclasses generation)Faster
TestingHarder (mocking tools)Easier
External dependenciesCGLIBnone

Can I combine CGLIB and Interfaces?

Yes, you can easily switch between CGLIB and Interfaces, Spring will manage the magic.
You could for example, start using Spring Components without interfaces (using CGLIB) when you prototype your application and create the interfaces when you are consolidating / refactoring the codebase.

How Spring proxies the classes

https://docs.spring.io/spring-framework/reference/core/aop/proxying.html

Do you really like CGLIB? You can force Spring to use it

If you really need CGLIB and you want to force it everywhere you can ask Spring to use it with:

spring.aop.proxy-target-class=true 

CGLIB and Ahead-of-Time Compilation

CGLIB modifies the classes at Runtime for this reason it doesn't work with AOT (required for native) out of the box.
Spring AOT needs to generate these proxies at build time to be used in GraalVM.

Who else is using CGLIB?

CGLIB was a popular library in the Java ecosystem. Many frameworks were using it, but ByteBuddy replaced in most of them.

FrameworkUses CGLIB?Comment
SpringYesClass based proxies
HibernateNoIt migrated from CGLIB to ByteBuddy
MockitoNoMoved from CGLIB to ByteBuddy
QuarkusNoNever used CGLIB

Conclusion: Which one should we use?

CGLIB enables Spring to generate proxies for concrete classes, allowing for more flexibility in bean design.
However, this power comes at a cost: the bytecode manipulation it relies on can lead to unexpected behavior, especially in complex inheritance hierarchies or when using final methods.
It’s a valuable tool, but one that we need to handle with care.

The GitHub of Spring is filled with hundreds of issues or questions about CGLIB.

For quick development and small teams, CGLIB can help reduce boilerplate. For large, maintainable systems or where
mocking and testing are priorities, interfaces (and JDK proxies) are the safer bet.


WebApp built by Marco using Java 24 - Hosted in Switzerland