java - 启用 SSL 的 Spring Boot 阻塞连接池

标签 java spring spring-boot ssl spring-data-jpa

我有一个使用自签名证书启用 SSL 的 Spring Boot 应用程序(版本 2.5.3)。
一个端点用于使用 StreamingResponseBody 在客户端下载文件。
问题
问题是,当用户通过此端点请求文件时,连接池不会被清理。
在这里展示问题的工作示例:
https://github.com/smotastic/blocked-connection-pool

@GetMapping("/ping")
public ResponseEntity<StreamingResponseBody> ping() {
    // service.findSomeFile(...)
    StreamingResponseBody body = new StreamingResponseBody() {
        
        @Override
        public void writeTo(OutputStream outputStream) throws IOException {
            // outputStream.write(someFile);
        }
    };
    return ResponseEntity.ok(body);
}
调用此函数并打开 Hikari 连接池的调试日志记录后,将记录以下内容。
Pool stats (total=10, active=1, idle=9, waiting=0)
如您所见,一个连接处于 Activity 状态,并且永远不会再次释放。如果我再调用此端点 9 次,则连接池已满,任何后续请求都将超时。
到目前为止我发现了什么
启用 ssl 的应用程序、对服务或存储库的调用以及 StreamingResponseBody 的返回值的组合似乎是我的问题。
一旦我关闭这些因素之一,问题就会消失,并且连接会按预期释放。
// SecurityConfig.java
@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().anyRequest().permitAll();
    http.requiresChannel().anyRequest().requiresSecure(); // turning this off 'solves' the problem
}
在示例中,我提供了一个简单的 FooEntity 和一个 FooRepository,在这里我只调用了 count 方法。
我想这会打开一个新事务并在这里引发错误。
// Controller.java
@Autowired
FooRepository fooRepo;

@GetMapping("/ping")
public ResponseEntity<StreamingResponseBody> ping() {
    fooRepo.count(); // removing this line 'solves' the error
    StreamingResponseBody body = new StreamingResponseBody() {
            
        @Override
        public void writeTo(OutputStream outputStream) throws IOException {
          // outStream.write(...)
        }
    };
    return ResponseEntity.ok(body);
}
在这种情况下,FooRepository 只是 Spring 的一个简单的 CrudRepository,没有额外的功能。
// FooRepository.java
@Repository
public interface FooRepository extends CrudRepository<Foo, Long>{

}
FooEntity 是一个带有 id 的简单实体。
// Foo.java
@Entity
public class Foo {

    @GeneratedValue
    @Id
    private Long id;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
    
}
在此示例中,我使用的是 h2 数据源,但我也尝试使用 postgres。
两者都不起作用。
# application.properties
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create

spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
ssl 通过以下配置启用。
# https via self signed certificate
server.ssl.key-store-type=${SSL_KEY_STORE_TYPE:PKCS12}
# The path to the keystore containing the certificate
server.ssl.key-store=${SSL_KEY_STORE:classpath:identity.p12}
# The password used to generate the certificate
server.ssl.key-store-password=${SSL_KEY_STORE_PASSWORD:hello}
# The alias mapped to the certificate
server.ssl.key-alias=${SSL_KEY_ALIAS:mykey}
server.ssl.enabled=${SSL_ENABLED:true}
该证书是在我的 Windows 10 机器上创建的自签名证书。
此外,Hikari 连接池似乎不是问题。我还尝试了 Tomcat JDBC 连接池。池仍然被阻塞。
# application.properties
spring.datasource.type=org.apache.tomcat.jdbc.pool.DataSource

最佳答案

关于java - 启用 SSL 的 Spring Boot 阻塞连接池,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68798722/

相关文章:

java - Spring中的bean实例化和依赖注入(inject)

java - Spring XML 406 错误

java - 我需要做哪些设置才能在 Spring 中使用 JSR-303 注释?

java - 如何配置 Spring-WS 以使用 JAXB Marshaller?

java - 如何在application.properties文件中设置默认值?

java - dspace 导入元数据确认更改不应用它们

java - 是否可以将 'see' 对象图用于垃圾回收?

java - 不加载整个对象

java - 简单的 Spring 应用程序返回路由错误

java - Vue SPA 与 Spring Boot,分离与否