最近在使用 Spring Boot 快速搭建项目,用来学习 Spring Data MongoDB 库,在运行过程中抛出如下错误信息:
org.apache.tomcat.jni.LibraryNotFoundError: Can't load library: D:\learn\spring_data\springdata_mongodb\springdata_mongodb_demo4\bin\tcnative-2.dll, Can't load library: D:\learn\spring_data\springdata_mongodb\springdata_mongodb_demo4\bin\libtcnative-2.dll, Can't load library: D:\learn\spring_data\springdata_mongodb\springdata_mongodb_demo4\bin\tcnative-1.dll, Can't load library: D:\learn\spring_data\springdata_mongodb\springdata_mongodb_demo4\bin\libtcnative-1.dll, no tcnative-2 in java.library.path, no libtcnative-2 in java.library.path, no tcnative-1 in java.library.path, no libtcnative-1 in java.library.path at org.apache.tomcat.jni.Library.<init>(Library.java:93) ~[tomcat-embed-core-9.0.68.jar:9.0.68] at org.apache.tomcat.jni.Library.initialize(Library.java:234) ~[tomcat-embed-core-9.0.68.jar:9.0.68] at org.apache.catalina.core.AprLifecycleListener.init(AprLifecycleListener.java:201) [tomcat-embed-core-9.0.68.jar:9.0.68] at org.apache.catalina.core.AprLifecycleListener.isAprAvailable(AprLifecycleListener.java:112) [tomcat-embed-core-9.0.68.jar:9.0.68] at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getDefaultServerLifecycleListeners(TomcatServletWebServerFactory.java:182) [spring-boot-2.7.5.jar:2.7.5] at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.<init>(TomcatServletWebServerFactory.java:129) [spring-boot-2.7.5.jar:2.7.5] at org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat.tomcatServletWebServerFactory(ServletWebServerFactoryConfiguration.java:76) [spring-boot-autoconfigure-2.7.5.jar:2.7.5] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_45] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_45] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_45] at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_45] at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) [spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) [spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:638) [spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352) [spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195) [spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) [spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) [spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) [spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$517/633079302.getObject(Unknown Source) [spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) [spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) [spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) [spring-beans-5.3.23.jar:5.3.23] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955) [spring-beans-5.3.23.jar:5.3.23] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) [spring-context-5.3.23.jar:5.3.23] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) [spring-context-5.3.23.jar:5.3.23] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) [spring-boot-2.7.5.jar:2.7.5] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) [spring-boot-2.7.5.jar:2.7.5] at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) [spring-boot-2.7.5.jar:2.7.5] at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:132) [spring-boot-test-2.7.5.jar:2.7.5] at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:141) [spring-test-5.3.23.jar:5.3.23] at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:90) [spring-test-5.3.23.jar:5.3.23] at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124) [spring-test-5.3.23.jar:5.3.23] at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190) [spring-test-5.3.23.jar:5.3.23] at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132) [spring-test-5.3.23.jar:5.3.23] at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:248) [spring-test-5.3.23.jar:5.3.23] at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:138) [spring-test-5.3.23.jar:5.3.23] at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$8(ClassBasedTestDescriptor.java:363) [junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor$$Lambda$373/438589491.execute(Unknown Source) [junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:368) [junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$9(ClassBasedTestDescriptor.java:363) [junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor$$Lambda$372/1551945522.accept(Unknown Source) [junit-jupiter-engine-5.8.2.jar:5.8.2] at java.util.stream.StreamSpliterators$WrappingSpliterator$$Lambda$253/1607305514.accept(Unknown Source) [na:1.8.0_45] at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) [na:1.8.0_45] at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175) [na:1.8.0_45] at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374) [na:1.8.0_45] at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:512) [na:1.8.0_45] at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502) [na:1.8.0_45] at java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312) [na:1.8.0_45] at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:743) [na:1.8.0_45] at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:742) [na:1.8.0_45] at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580) [na:1.8.0_45] at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:362) [junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$instantiateAndPostProcessTestInstance$6(ClassBasedTestDescriptor.java:283) [junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor$$Lambda$371/1293677337.execute(Unknown Source) [junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:282) [junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$4(ClassBasedTestDescriptor.java:272) [junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor$$Lambda$366/633240419.get(Unknown Source) [junit-jupiter-engine-5.8.2.jar:5.8.2] at java.util.Optional.orElseGet(Optional.java:267) [na:1.8.0_45] at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$5(ClassBasedTestDescriptor.java:271) [junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor$$Lambda$272/1392906938.getTestInstances(Unknown Source) [junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31) [junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:102) [junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor$$Lambda$365/1916575798.execute(Unknown Source) [junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:101) [junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:66) [junit-jupiter-engine-5.8.2.jar:5.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$2(NodeTestTask.java:123) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask$$Lambda$209/2095490653.execute(Unknown Source) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:123) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:90) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService$$Lambda$228/603856241.accept(Unknown Source) [junit-platform-engine-1.8.2.jar:1.8.2] at java.util.ArrayList.forEach(ArrayList.java:1249) [na:1.8.0_45] at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask$$Lambda$224/1693847660.execute(Unknown Source) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask$$Lambda$223/863125040.invoke(Unknown Source) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask$$Lambda$222/2092769598.execute(Unknown Source) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService$$Lambda$228/603856241.accept(Unknown Source) [junit-platform-engine-1.8.2.jar:1.8.2] at java.util.ArrayList.forEach(ArrayList.java:1249) [na:1.8.0_45] at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask$$Lambda$224/1693847660.execute(Unknown Source) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask$$Lambda$223/863125040.invoke(Unknown Source) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask$$Lambda$222/2092769598.execute(Unknown Source) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) [junit-platform-engine-1.8.2.jar:1.8.2] at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107) [junit-platform-launcher-1.8.2.jar:1.8.2] at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88) [junit-platform-launcher-1.8.2.jar:1.8.2] at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54) [junit-platform-launcher-1.8.2.jar:1.8.2] at org.junit.platform.launcher.core.EngineExecutionOrchestrator$$Lambda$185/1568059495.accept(Unknown Source) [junit-platform-launcher-1.8.2.jar:1.8.2] at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67) [junit-platform-launcher-1.8.2.jar:1.8.2] at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52) [junit-platform-launcher-1.8.2.jar:1.8.2] at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114) [junit-platform-launcher-1.8.2.jar:1.8.2] at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86) [junit-platform-launcher-1.8.2.jar:1.8.2] at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86) [junit-platform-launcher-1.8.2.jar:1.8.2] at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53) [junit-platform-launcher-1.8.2.jar:1.8.2] at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:74) [junit5-rt.jar:na] at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) [junit-rt.jar:na] at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) [junit-rt.jar:na] at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) [junit-rt.jar:na]
从上面的错误日志可以得知,错误是由于不能加载 tcnative-2.dll 本地库导致的。
因为 Tomcat 中的 connector 为了提高性能,采用了加载与操作系统绑定(非跨平台)的本地库的方式,比如:Windows 系统中就是 .dll 动态链接库。
默认会去 Tomcat 的 bin 目录下去找,但是由于 Spring Boot 的 Tomcat 是嵌入式的,没有这些 .dll,所以需要自己去官网下载,并解压放到 C:\Windows\System32\ 目录下。
Apache Tomcat Native Library 是与 Apache Tomcat 一起使用的可选组件,它允许 Tomcat 使用 Open SSL 作为 JSSE 的替代品来支持 TLS 连接。说白了,Tomcat Native 就是一套和操作系统紧密结合的库,不同类型的操作系统 Tomcat Native 就会不同,如:Windows 下就是动态链接库,Linux 系统就是 .so 库文件。使用 Tomcat Native 可以调用操作系统底层的能力,提升 Tomcat 的性能。
更多关于 Tomcat Native 的信息,请参考:https://tomcat.apache.org/native-doc/
访问 http://archive.apache.org/dist/tomcat/tomcat-connectors/native/1.2.14/binaries/ 地址,下载 Tomcat Native,然后解压压缩包。将 tc-native-1.dll 和 openssl.exe 拷贝到 C:\Windows\System32\ 目录下。如下图: