others-how to solve java.lang.UnsatisfiedLinkError when adding http/2 support for springboot applications?
1. Purpose
In this post, I will show you how to solve java.lang.UnsatisfiedLinkError when adding http/2 support for springboot applications.
Here is the detail error stacktrace:
[root@local springboot2-mvc]# ./start.sh
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.2.RELEASE)
2023-08-31 14:18:18.359 INFO 30021 --- [ main] springboot2.mvc.Application : Starting Application on local.server.harbor with PID 30021 (/root/http2/springboot2-mvc/springboot2-mvc-1.0-exec.jar started by root in /root/http2/springboot2-mvc)
2023-08-31 14:18:18.362 INFO 30021 --- [ main] springboot2.mvc.Application : No active profile set, falling back to default profiles: default
2023-08-31 14:18:18.453 INFO 30021 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@22a71081: startup date [Thu Aug 31 14:18:18 CST 2023]; root of context hierarchy
2023-08-31 14:18:19.540 WARN 30021 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library failed to load. The error reported was [/usr/local/apr/lib/libtcnative-1.so.0.2.38: /usr/local/apr/lib/libtcnative-1.so.0.2.38: undefined symbol: BN_get_rfc3526_prime_8192]
java.lang.UnsatisfiedLinkError: /usr/local/apr/lib/libtcnative-1.so.0.2.38: /usr/local/apr/lib/libtcnative-1.so.0.2.38: undefined symbol: BN_get_rfc3526_prime_8192
at java.lang.ClassLoader$NativeLibrary.load(Native Method) ~[na:1.8.0_231]
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1934) ~[na:1.8.0_231]
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1850) ~[na:1.8.0_231]
at java.lang.Runtime.loadLibrary0(Runtime.java:870) ~[na:1.8.0_231]
at java.lang.System.loadLibrary(System.java:1122) ~[na:1.8.0_231]
at org.apache.tomcat.jni.Library.<init>(Library.java:42) ~[tomcat-embed-core-8.5.31.jar!/:8.5.31]
at org.apache.tomcat.jni.Library.initialize(Library.java:178) ~[tomcat-embed-core-8.5.31.jar!/:8.5.31]
at org.apache.catalina.core.AprLifecycleListener.init(AprLifecycleListener.java:198) [tomcat-embed-core-8.5.31.jar!/:8.5.31]
at org.apache.catalina.core.AprLifecycleListener.isAprAvailable(AprLifecycleListener.java:107) [tomcat-embed-core-8.5.31.jar!/:8.5.31]
at org.apache.catalina.connector.Connector.setProtocol(Connector.java:582) [tomcat-embed-core-8.5.31.jar!/:8.5.31]
at org.apache.catalina.connector.Connector.<init>(Connector.java:74) [tomcat-embed-core-8.5.31.jar!/:8.5.31]
at springboot2.mvc.config.TomcatConfig$1.customize(TomcatConfig.java:30) [classes!/:na]
at springboot2.mvc.config.TomcatConfig$1.customize(TomcatConfig.java:24) [classes!/:na]
at org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor.lambda$postProcessBeforeInitialization$0(WebServerFactoryCustomizerBeanPostProcessor.java:78) [spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
at org.springframework.boot.util.LambdaSafe$Callbacks.lambda$null$0(LambdaSafe.java:291) ~[spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
at org.springframework.boot.util.LambdaSafe$LambdaSafeCallback.invoke(LambdaSafe.java:162) ~[spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
at org.springframework.boot.util.LambdaSafe$Callbacks.lambda$invoke$1(LambdaSafe.java:290) ~[spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
at java.util.ArrayList.forEach(ArrayList.java:1257) ~[na:1.8.0_231]
at java.util.Collections$UnmodifiableCollection.forEach(Collections.java:1082) ~[na:1.8.0_231]
at org.springframework.boot.util.LambdaSafe$Callbacks.invoke(LambdaSafe.java:289) ~[spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
at org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor.postProcessBeforeInitialization(WebServerFactoryCustomizerBeanPostProcessor.java:78) [spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
at org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor.postProcessBeforeInitialization(WebServerFactoryCustomizerBeanPostProcessor.java:61) [spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:422) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1698) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:579) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:501) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getWebServerFactory(ServletWebServerApplicationContext.java:214) ~[spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:178) ~[spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:152) ~[spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:544) ~[spring-context-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) ~[spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:395) ~[spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:327) ~[spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1255) ~[spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1243) ~[spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
at springboot2.mvc.Application.main(Application.java:13) ~[classes!/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_231]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_231]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_231]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_231]
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) ~[springboot2-mvc-1.0-exec.jar:na]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) ~[springboot2-mvc-1.0-exec.jar:na]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) ~[springboot2-mvc-1.0-exec.jar:na]
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51) ~[springboot2-mvc-1.0-exec.jar:na]
2023-08-31 14:18:19.669 INFO 30021 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8443 (https) 8082 (http)
The core error is:
2023-08-31 14:18:19.540 WARN 30021 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library failed to load. The error reported was [/usr/local/apr/lib/libtcnative-1.so.0.2.38: /usr/local/apr/lib/libtcnative-1.so.0.2.38: undefined symbol: BN_get_rfc3526_prime_8192]
java.lang.UnsatisfiedLinkError: /usr/local/apr/lib/libtcnative-1.so.0.2.38: /usr/local/apr/lib/libtcnative-1.so.0.2.38: undefined symbol: BN_get_rfc3526_prime_8192
Here is the /usr/local/apr/lib
:
[root@local springboot2-mvc]# ll /usr/local/apr/lib
Total 8360
-rw-r--r--. 1 root root 10110 8月 30 17:55 apr.exp
drwxr-xr-x. 2 root root 111 8月 30 17:56 apr-util-1
-rw-r--r--. 1 root root 5856 8月 30 17:56 aprutil.exp
-rw-r--r--. 1 root root 2058510 8月 30 17:55 libapr-1.a
-rwxr-xr-x. 1 root root 971 8月 30 17:55 libapr-1.la
lrwxrwxrwx. 1 root root 17 8月 30 17:55 libapr-1.so -> libapr-1.so.0.6.5
lrwxrwxrwx. 1 root root 17 8月 30 17:55 libapr-1.so.0 -> libapr-1.so.0.6.5
-rwxr-xr-x. 1 root root 1146040 8月 30 17:55 libapr-1.so.0.6.5
-rw-r--r--. 1 root root 1348480 8月 30 17:56 libaprutil-1.a
-rwxr-xr-x. 1 root root 1038 8月 30 17:56 libaprutil-1.la
lrwxrwxrwx. 1 root root 21 8月 30 17:56 libaprutil-1.so -> libaprutil-1.so.0.6.3
lrwxrwxrwx. 1 root root 21 8月 30 17:56 libaprutil-1.so.0 -> libaprutil-1.so.0.6.3
-rwxr-xr-x. 1 root root 811144 8月 30 17:56 libaprutil-1.so.0.6.3
-rw-r--r--. 1 root root 1972860 8月 30 18:02 libtcnative-1.a
-rwxr-xr-x. 1 root root 1054 8月 30 18:02 libtcnative-1.la
lrwxrwxrwx. 1 root root 23 8月 30 18:02 libtcnative-1.so -> libtcnative-1.so.0.2.38
lrwxrwxrwx. 1 root root 23 8月 30 18:02 libtcnative-1.so.0 -> libtcnative-1.so.0.2.38
-rwxr-xr-x. 1 root root 1177776 8月 30 18:02 libtcnative-1.so.0.2.38
drwxr-xr-x. 2 root root 43 8月 30 17:56 pkgconfig
The tomcat engine springboot using is:
Starting Servlet Engine: Apache Tomcat/8.5.31
2. Solution
2.1 What is libtcnative
?
Tomcat can use the Apache Portable Runtime to provide superior scalability, performance, and better integration with native server technologies. The Apache Portable Runtime is a highly portable library that is at the heart of Apache HTTP Server 2.x. APR has many uses, including access to advanced IO functionality (such as sendfile, epoll and OpenSSL), OS level functionality (random number generation, system status, etc), and native process handling (shared memory, NT pipes and Unix sockets).
These features allows making Tomcat a general purpose webserver, will enable much better integration with other native web technologies, and overall make Java much more viable as a full fledged webserver platform rather than simply a backend focused technology.
2.2 Why need libtcnative
?
Spring Boot ships by default with Tomcat 8.5.x. With that version, HTTP/2 is only supported if the libtcnative library and its dependencies are installed on the host operating system.
The library folder must be made available, if not already, to the JVM library path. You can do so with a JVM argument such as -Djava.library.path=/usr/local/opt/tomcat-native/lib. More on this in the official Tomcat documentation.
2.3 The solution
The tomcat I used to install libtcnative
is apache-tomcat-8.5.93
, is that the problem?
Try to install tomcat native again:
yum install tomcat-native
then query its install directory:
rpm -ql tomcat-native
then change the startup script:
java -cp . -Djava.library.path=/usr/lib64/ -jar *.jar
Then start springboot again, it works~
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.2.RELEASE)
2023-08-31 15:39:54.415 INFO 32466 --- [ main] springboot2.mvc.Application : Starting Application on local.server.harbor with PID 32466 (/root/http2/springboot2-mvc/springboot2-mvc-1.0-exec.jar started by root in /root/http2/springboot2-mvc)
2023-08-31 15:39:54.420 INFO 32466 --- [ main] springboot2.mvc.Application : No active profile set, falling back to default profiles: default
2023-08-31 15:39:54.504 INFO 32466 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@769c9116: startup date [Thu Aug 31 15:39:54 CST 2023]; root of context hierarchy
2023-08-31 15:39:55.653 INFO 32466 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8443 (https) 8082 (http)
2023-08-31 15:39:55.681 INFO 32466 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-08-31 15:39:55.681 INFO 32466 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.31
2023-08-31 15:39:55.689 INFO 32466 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : Loaded APR based Apache Tomcat Native library [1.2.35] using APR version [1.4.8].
2023-08-31 15:39:55.690 INFO 32466 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].
2023-08-31 15:39:55.690 INFO 32466 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : APR/OpenSSL configuration: useAprConnector [false], useOpenSSL [true]
2023-08-31 15:39:55.694 INFO 32466 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : OpenSSL successfully initialized [OpenSSL 1.0.2k-fips 26 Jan 2017]
2023-08-31 15:39:55.768 INFO 32466 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-08-31 15:39:55.768 INFO 32466 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1268 ms
2023-08-31 15:39:55.895 INFO 32466 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/]
2023-08-31 15:39:55.899 INFO 32466 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2023-08-31 15:39:55.899 INFO 32466 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2023-08-31 15:39:55.899 INFO 32466 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2023-08-31 15:39:55.899 INFO 32466 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
Now test it:
[root@local webhook_service]# curl -k -vvv https://localhost:8443/getMapResult
* About to connect() to localhost port 8443 (#0)
* Trying ::1...
* Connected to localhost (::1) port 8443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
* subject: CN=xx,OU=xx,O=xx,L=xx,ST=xx,C=xx
* start date: 8月 30 08:32:05 2023 GMT
* expire date: 8月 27 08:32:05 2033 GMT
* common name: xx
* issuer: CN=xx,OU=xx,O=xx,L=xx,ST=xx,C=xx
> GET /getMapResult HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:8443
> Accept: */*
>
< H2 200
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Thu, 31 Aug 2023 07:40:30 GMT
<
* Connection #0 to host localhost left intact
3. Summary
In this post, I demonstrated how to solve java.lang.UnsatisfiedLinkError when adding http/2 support for springboot applications . That’s it, thanks for your reading.