Affected spring version: 6.1.1(native image)
r2dbc connectionFactory will clean up the connection pool when the application exits, but at this time it will report an error:
2023-12-12T17:15:53.545+08:00 WARN 48253 --- [ionShutdownHook] o.s.b.f.support.DisposableBeanAdapter : Failed to invoke custom destroy method 'dispose' on bean with name 'connectionFactory'
org.graalvm.nativeimage.MissingReflectionRegistrationError: The program tried to reflectively invoke method public abstract void reactor.core.Disposable.dispose() without it being registered for runtime reflection. Add it to the reflection metadata to solve this problem. See https://www.graalvm.org/latest/reference-manual/native-image/metadata/#reflection for help.
at org.graalvm.nativeimage.builder/com.oracle.svm.core.reflect.MissingReflectionRegistrationUtils.forQueriedOnlyExecutable(MissingReflectionRegistrationUtils.java:97) ~[na:na]
at java.base@17.0.8/java.lang.reflect.Method.acquireMethodAccessor(Method.java:77) ~[demo:na]
at java.base@17.0.8/java.lang.reflect.Method.invoke(Method.java:566) ~[demo:na]
at org.springframework.beans.factory.support.DisposableBeanAdapter.invokeCustomDestroyMethod(DisposableBeanAdapter.java:316) ~[na:na]
at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:249) ~[na:na]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:587) ~[demo:6.1.1]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:559) ~[demo:6.1.1]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:1200) ~[demo:6.1.1]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:520) ~[demo:6.1.1]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:1193) ~[demo:6.1.1]
at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1125) ~[demo:6.1.1]
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1086) ~[demo:6.1.1]
at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.doClose(ReactiveWebServerApplicationContext.java:149) ~[demo:3.2.0]
at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:1037) ~[demo:6.1.1]
at org.springframework.boot.SpringApplicationShutdownHook.closeAndWait(SpringApplicationShutdownHook.java:145) ~[na:na]
at java.base@17.0.8/java.lang.Iterable.forEach(Iterable.java:75) ~[demo:na]
at org.springframework.boot.SpringApplicationShutdownHook.run(SpringApplicationShutdownHook.java:114) ~[na:na]
at java.base@17.0.8/java.lang.Thread.run(Thread.java:833) ~[demo:na]
at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:807) ~[demo:na]
at org.graalvm.nativeimage.builder/com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:210) ~[na:na]
I have written some code to reproduce this problem: https://github.com/czp3009/spring-native-dispose-issue-reproduction
Native compile and execute the application and then terminate it to see the exception
I guess it's related to this issue: https://github.com/spring-projects/spring-framework/issues/31278
Comment From: snicoll
@czp3009 thanks for the report and the sample but I believe that the repo is either private or its URL is misspelled. Can you please check?
Comment From: czp3009
@snicoll oh, sorry, i forgot to change repository visibility. please try again.
Comment From: snicoll
It's a bit strange. I can see a hint being generated for the proper target class:
{
"name": "io.r2dbc.pool.ConnectionPool",
"queryAllPublicMethods": true,
"queryAllDeclaredMethods": true,
"methods": [
{
"name": "dispose",
"parameterTypes": [ ]
}
]
}
I don't really understand yet why it insists on having a hint for the interface.
Comment From: snicoll
This sample worked with Spring Boot 3.1.x
(and Spring Framework 6.0.x
) so I've flagged it as a regression.
The only thing that was different was "queryAllPublicMethods": true
missing in the 6.0.x
version. I've added it manually in the sample and it works still.
Comment From: snicoll
Looking at the code it was always meant to be invoked from the interface. It looks like in 6.0.x
the interface was hidden and things were working as a side effect of that. I've made sure the interface method has the appropriate hint. With a snapshot, that sample now works. Thanks again for the report @czp3009.