I'm not sure I understood the gains of CGLIB as you've presented them in the question.
Both dynamic proxy and CGLIB are created in runtime, it's not relevant to compile-time at all.
Basically, the major drawback of CGLIB is performance.
There are two aspects of performance that can be more or less important depending on the domain:
- The Cost of creation of a proxy object
- The cost of the Method call on a proxy.
Now, In both cases, the dynamic proxy mechanism is way more lightweight than a CGLIB proxy. That's why spring up to version 5 (mentioned in the question tag) has attempted to create Dynamic proxy if there was an interface and only if it wasn't possible it wrapped the real object with CGLIB.
This has changed in Spring 5 in favor of using CGLIB in any case but there is still a flag that can bring back the old behavior.
Interesting that CGLIB has a kind of advantage that you haven't mentioned that turned to be important to Spring (well, maybe that was the reason of the behavior change in Spring 5, I can't say for sure):
Many companies don't bother to create interfaces for the services and work directly by the implementation, or even if they do - they do not use injection by interface:
public interface MyService {
void foo();
}
@Component
public class MyServiceImpl implements MyService {
public void foo() {... whatever...}
}
@Component
public class AnotherService {
@Autowired // note, this is not an injection by inteface
private MyServiceImpl service;
public void bar() {
// do something
service.foo();
// do something else
}
}
Now, if you'll use a dynamic proxy (which in general could be used if the application code was using the injection by interface) - you'll generate something that implements the interface MyService but can't be injected into AnotherService because the generated proxy doesn't extend MyServiceImpl class. In this case, the CGLIB is the only viable solution.