smo*_*tic 5 java ssl spring spring-data-jpa spring-boot
我有一个使用自签名证书启用 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);
}
Run Code Online (Sandbox Code Playgroud)
调用此方法并打开 Hikari 连接池的调试日志后,将记录以下内容。
Pool stats (total=10, active=1, idle=9, waiting=0)
Run Code Online (Sandbox Code Playgroud)
如您所见,一个连接处于活动状态,并且永远不会再次释放。如果我再调用此端点 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
}
Run Code Online (Sandbox Code Playgroud)
在示例中,我提供了一个简单的 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);
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,FooRepository 只是一个来自 Spring 的简单 CrudRepository,没有额外的功能。
// FooRepository.java
@Repository
public interface FooRepository extends CrudRepository<Foo, Long>{
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,我使用了一个 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
Run Code Online (Sandbox Code Playgroud)
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}
Run Code Online (Sandbox Code Playgroud)
该证书是在我的 Windows 10 机器上创建的自签名证书。
此外,Hikari 连接池似乎不是问题。我还尝试了 Tomcat JDBC 连接池。池仍然被阻塞。
# application.properties
spring.datasource.type=org.apache.tomcat.jdbc.pool.DataSource
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
71 次 |
| 最近记录: |