为啥 spring-boot-starter-jdbc 会破坏我的 REST 端点?

Posted

技术标签:

【中文标题】为啥 spring-boot-starter-jdbc 会破坏我的 REST 端点?【英文标题】:Why is spring-boot-starter-jdbc breaking my REST endpoints?为什么 spring-boot-starter-jdbc 会破坏我的 REST 端点? 【发布时间】:2021-07-18 18:13:23 【问题描述】:

为了运行简单的 SQL 命令(它们是我的 pom.xml 文件中的最后两个依赖项),我正在实现两个插件,用于对 springboot 项目进行 DB 访问。到目前为止,我已经开发了几个 REST 端点,没有任何问题。生成的war文件托管在Linux机器上的Tomcat中。

这是我的 pom.xml 文件的摘录:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/>
    </parent>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>        

        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>3.11.0</version>
        </dependency>

        <dependency>
            <groupId>com.jcraft</groupId>
            <artifactId>jsch</artifactId>
            <version>0.1.55</version>
        </dependency>

        <dependency>
            <groupId>com.googlecode.json-simple</groupId>
            <artifactId>json-simple</artifactId>
            <version>1.1.1</version>
        </dependency>

        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>mssql-jdbc</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

    </dependencies>

这是 Tomcat 版本:

Using CATALINA_BASE:   /apps/tomcat/apache-tomcat-9.0.34
Using CATALINA_HOME:   /apps/tomcat/apache-tomcat-9.0.34
Using CATALINA_TMPDIR: /apps/tomcat/apache-tomcat-9.0.34/temp
Using JRE_HOME:        /usr
Using CLASSPATH:       /apps/tomcat/apache-tomcat-9.0.34/bin/bootstrap.jar:/apps/tomcat/apache-tomcat-9.0.34/bin/tomcat-juli.jar
Server version: Apache Tomcat/9.0.34
Server built:   Apr 3 2020 12:02:52 UTC
Server number:  9.0.34.0
OS Name:        Linux
OS Version:     3.10.0-1160.24.1.el7.x86_64
Architecture:   amd64
JVM Version:    1.8.0_275-b01
JVM Vendor:     Red Hat, Inc.

Apache Maven version 3.6.3

编译(使用 Maven)后,一切看起来都很好,没有构建错误,构建了 war 文件,一切都很好,就像任何其他以前的构建一样。直到现在,如果我删除“spring-boot-starter-jdbc”依赖项,我尝试点击的任何端点都会返回 404。

这是我正在关注的演练: https://www.codejava.net/frameworks/spring-boot/connect-to-microsoft-sql-server-examples

这些是使用和不使用依赖项进行部署时的日志。

没有依赖的日志:

==> catalina.2021-04-25.log <==
25-Apr-2021 01:09:51.912 INFO [Catalina-utility-2] org.apache.catalina.startup.HostConfig.undeploy Undeploying context [/ciamdev]

==> localhost.2021-04-25.log <==
25-Apr-2021 01:09:51.917 INFO [Catalina-utility-2] org.apache.catalina.core.ApplicationContext.log Destroying Spring FrameworkServlet 'dispatcherServlet'
25-Apr-2021 01:09:51.940 INFO [Catalina-utility-2] org.apache.catalina.core.ApplicationContext.log Closing Spring root WebApplicationContext

==> catalina.2021-04-25.log <==
25-Apr-2021 01:09:52.079 INFO [Catalina-utility-2] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/apps/tomcat/apache-tomcat-9.0.34/webapps/ciamdev.war]
25-Apr-2021 01:09:54.783 INFO [Catalina-utility-2] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.

==> localhost.2021-04-25.log <==
25-Apr-2021 01:09:55.017 INFO [Catalina-utility-2] org.apache.catalina.core.ApplicationContext.log 2 Spring WebApplicationInitializers detected on classpath
25-Apr-2021 01:09:58.028 INFO [Catalina-utility-2] org.apache.catalina.core.ApplicationContext.log Initializing Spring embedded WebApplicationContext

==> catalina.2021-04-25.log <==
25-Apr-2021 01:09:59.704 INFO [Catalina-utility-2] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/apps/tomcat/apache-tomcat-9.0.34/webapps/ciamdev.war] has finished in [7,625] ms

具有依赖关系的日志:

==> catalina.2021-04-25.log <==
25-Apr-2021 01:12:59.805 INFO [Catalina-utility-1] org.apache.catalina.startup.HostConfig.undeploy Undeploying context [/ciamdev]

==> localhost.2021-04-25.log <==
25-Apr-2021 01:12:59.841 INFO [Catalina-utility-1] org.apache.catalina.core.ApplicationContext.log Closing Spring root WebApplicationContext

==> catalina.2021-04-25.log <==
25-Apr-2021 01:12:59.923 INFO [Catalina-utility-1] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/apps/tomcat/apache-tomcat-9.0.34/webapps/ciamdev.war]
25-Apr-2021 01:13:03.342 INFO [Catalina-utility-1] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.

==> localhost.2021-04-25.log <==
25-Apr-2021 01:13:03.536 INFO [Catalina-utility-1] org.apache.catalina.core.ApplicationContext.log 2 Spring WebApplicationInitializers detected on classpath
25-Apr-2021 01:13:07.432 INFO [Catalina-utility-1] org.apache.catalina.core.ApplicationContext.log Initializing Spring embedded WebApplicationContext

==> catalina.2021-04-25.log <==
25-Apr-2021 01:13:09.189 SEVERE [Catalina-utility-1] org.apache.catalina.startup.HostConfig.deployWAR Error deploying web application archive [/apps/tomcat/apache-tomcat-9.0.34/webapps/ciamdev.war]
        java.lang.IllegalStateException: Error starting child
                at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:720)
                at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:690)
                at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:705)
                at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:978)
                at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1849)
                at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
                at java.util.concurrent.FutureTask.run(FutureTask.java:266)
                at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
                at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
                at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:773)
                at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:427)
                at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1620)
                at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:305)
                at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:123)
                at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1151)
                at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1353)
                at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1357)
                at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1335)
                at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
                at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
                at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
                at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
                at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
                at java.lang.Thread.run(Thread.java:748)
        Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/ciamdev]]
                at org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:440)
                at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:198)
                at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:717)
                ... 25 more
        Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class
                at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:656)
                at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:636)
                at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338)
                at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177)
                at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557)
                at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
                at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
                at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
                at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
                at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
                at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879)
                at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)
                at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
                at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
                at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
                at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
                at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
                at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:152)
                at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:132)
                at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:92)
                at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:172)
                at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5140)
                at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
                ... 26 more
        Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class
                at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
                at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651)
                ... 48 more
        Caused by: org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class
                at org.springframework.boot.autoconfigure.jdbc.DataSourceProperties.determineDriverClassName(DataSourceProperties.java:233)
                at org.springframework.boot.autoconfigure.jdbc.DataSourceProperties.initializeDataSourceBuilder(DataSourceProperties.java:174)
                at org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration.createDataSource(DataSourceConfiguration.java:43)
                at org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Hikari.dataSource(DataSourceConfiguration.java:85)
                at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
                at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                at java.lang.reflect.Method.invoke(Method.java:498)
                at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
                ... 49 more
25-Apr-2021 01:13:09.190 INFO [Catalina-utility-1] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/apps/tomcat/apache-tomcat-9.0.34/webapps/ciamdev.war] has finished in [9,267] ms

我看到日志中提到了“dataSource”,这就是我在 application.properites 文件中的内容:

spring.datasource.url=jdbc:sqlserver://some-server.net;databaseName=somedbname
spring.datasource.username=serverusername
spring.datasource.password=1346794613

演练提供的是连接到数据库

3. Connect to SQL Server with Spring JDBC
4. Connect to SQL Server with Spring Data JPA

我正在尝试#3,因为它只是我需要执行的基本 SQL 命令。

我在寻找修复程序时没有发现类似的问题。

有其他人经历过吗?可能是什么问题?

提前致谢。

【问题讨论】:

【参考方案1】:

我在这篇文章中找到了解决方案: https://***.com/a/31199853/3247471

添加了这一行

@EnableAutoConfiguration(exclude=DataSourceAutoConfiguration.class)

在springboot应用类中像这样:

@SpringBootApplication
@EnableAutoConfiguration(exclude=DataSourceAutoConfiguration.class)
public class HealthcheckApiApplication extends SpringBootServletInitializer 
...

感谢 @justthink 为我指明了正确的方向。

【讨论】:

【参考方案2】:

Spring MVC (Springboot) 和许多其他 MVC 框架共享相同的概念,其中 Controller (C) 与 Model (M) 严格分开。因此,任何持久性模块 JDBC 都不太可能与您的控制器发生交互。在您的问题中,

只有现在我尝试点击的任何端点都会返回 404

我只能假设应用程序在这种情况下甚至都没有启动。

您可以在尝试启动并运行应用程序时发布 stact 跟踪。


还有一点需要注意,这可能与您的问题无关。在您关注的walkthrough 中,您可能需要添加@Repository

package net.codejava;
 
import org.springframework.data.jpa.repository.JpaRepository;
 
@Repository
public interface CustomerRepository extends JpaRepository<Customer, Long> 
 

所以这变成了一个 Spring Bean,你可以在某个地方进一步 autowire 它。


更新:检查您刚刚发布的堆栈跟踪后,我注意到driver class 是这里的问题。

Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: 
Factory method 'dataSource' threw exception; nested exception is 
org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: 
Failed to determine a suitable driver class

看到Failed to determine a suitable driver class了吗?它建议您定义一个驱动程序类。

对于 Microsoft sqlserver,请尝试在您的 .properties 配置文件中定义驱动程序类名称。例如,它可能是:

spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
# or
# spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver

另见https://springframework.guru/configuring-spring-boot-for-microsoft-sql-server/

请注意,驱动程序类名称可能会因版本而异。

【讨论】:

我将使用日志和 application.properties 的内容更新我的帖子 顺便说一句,我什至没有使用依赖项或尝试在代码中实例化任何内容,我首先只是尝试确保依赖项被导入并准备好使用。 @Raul Marquez 依赖项mssql-jdbc 通过检查.properties 文件中的配置来自动配置数据源。如果配置有任何问题,它会抱怨并停止您的应用程序运行。

以上是关于为啥 spring-boot-starter-jdbc 会破坏我的 REST 端点?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?

为啥需要softmax函数?为啥不简单归一化?

为啥 g++ 需要 libstdc++.a?为啥不是默认值?

为啥或为啥不在 C++ 中使用 memset? [关闭]

为啥临时变量需要更改数组元素以及为啥需要在最后取消设置?

为啥 CAP 定理中的 RDBMS 分区不能容忍,为啥它可用?