GraalVM native-image only supports JDK dynamic proxies when configured explicitly on interfaces.

For proxies on classes, typically created at runtime with CGLIB on the JVM, there is a need to create such proxies Ahead-Of-Time. That's what @aclement did in Spring Native: - Class proxies are configured by users via AotProxyHint (annotation) or NativeProxyEntry (programmatic) or inferred AOT by AotProxyNativeConfigurationProcessor - ConfigurationContributor#generateBuildTimeClassProxy is generating the configured class proxies using the infrastructure located here. - A DefaultAopProxyFactory#createAopProxy substitution is using the AOT generated class proxy when needed.

Spring Framework 6 should provide similar support for AOT generated class proxies, potentially by: - Leveraging ClassProxyHint to configure them - Deciding how the creation of the proxy should be implemented - Plug it into the AOT processing - Implement proper inferring if possible - Replace the substitution by proper handling in DefaultAopProxyFactory and/or other relevant classes

Comment From: aclement

Just a bit more context. I could have built my own proxy generation but it would have taken a while and I wasn't in a position to easily test it rigorously for all spring use cases. So I leveraged https://github.com/spring-projects/spring-framework/pull/1283 which replaced CGLIB with byte buddy because I knew that was passing the tests, and it would give me an easier route to pushing proxy generation to being something I could drive at build time rather than runtime. It had mechanisms for easily grabbing the bytecode for the proxy, and total control over the proxy naming (because when looking them up at runtime it had to exactly match what was created earlier).

Importantly it was also generating a more optimal proxy that was using less of the generated support classes for invoking some methods. For 'well known' interfaces that the proxy was implementing it was directly wiring up the invocations. Whereas CGLIB was using a general approach for all methods, leading to lots of new classes. (However, hand crafting could have also performed these optimizations, obviously).

The current version was definitely constructed as a building block. Ideally the necessary proxies could be more inferred rather than the user trying to work out what set of 'bits' they need to supply for proxy hints, or discovering it by trial and error when running the system is printing out the required hints.

Comment From: aclement

The commit encompassing all these changes in spring-native is https://github.com/spring-projects-experimental/spring-native/commit/af0e804e49887b77567721b73efebb18e2992e79

Comment From: sdeleuze

Related topic : Spring Native we currently relies on Hibernate Build-time enhancement to perform Hibernate bytecode manipulation at build time. I mention that because: - It could be interesting to see how they implemented that. - This seems not super actively maintained (for example, no Gradle Kotlin DSL support if I remember correctly). - Using that imply painful additional build configuration, we may be interested by a more integrated approach.

Maybe a point to discuss with @mp911de, @schauder and @christophstrobl.

Comment From: jhoeller

There is an initial commit coming to main now: This includes runtime storing of generated classes to a directory specified by the "cglib.generatedClasses" system property, to be picked up by the build process for further inclusion in a jar file (and ultimately in a native image). We also avoid lazy CGLIB fast-class generation now and replace the generated Enhancer and MethodWrapper key classes with equivalent record types. Last but not least, this introduces support for early type determination in InstantiationStrategy, AopProxy and SmartInstantiationAwareBeanPostProcessor - in order to trigger CGLIB class generation in refreshForAotProcessing (through early determineBeanType calls for bean definitions).