Spring Boot 2.1和Java 11中的Bean生命周期



我的项目正在从带有Java 8的Spring Boot 2.0.4迁移到带有Java 11的Spring Boots 2.1.0。当应用程序使用Spring Boot 2.0.4和Java 8构建并在Docker/Docker Compose中运行时,会调用@PostConstruct-带注释的方法,但在迁移到Spring Boot 2.1.0和Java 11之后,不再调用@PreDestroy-带注释的方式。

我已经尝试过从注释切换到实现这里描述的InitializingBeanDisposableBean,但没有调用DisposableBean.destroy方法。

我还尝试在javax.annotation-api 1.3.2版本中添加一个依赖项,得到了相同的结果。

如何复制:

使用生命周期bean创建一个最小的Spring应用程序:

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
@Component
public class Life implements InitializingBean, DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("--- Life.shutdown");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("--- Life.startup");
}
}

从目标子文件夹启动Spring应用程序:

cd target
java -jar demo-0.0.1-SNAPSHOT.jar

当使用Ctrl+C停止应用程序时,将调用DisposableBean.default。

返回父文件夹:

cd ..

使用Maven:启动Spring应用程序

mvn spring-boot:run

当使用Ctrl+C停止应用程序时,将调用DisposableBean.default。

Dockerfile:

FROM openjdk:11.0.1-jre-slim
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT java -jar /app.jar

构建、运行和停止Docker镜像:

docker build -t demo .
docker run -p 8080:8080 demo
docker ps
docker stats 3ca5b804ab13
docker stop 3ca5b804ab13
docker logs 3ca5b804ab13

当使用docker stop停止应用程序时,不会调用DisposableBean.default。

docker-compose.yml:

demo:
image: demo
ports:
- '8080:8080'

使用Docker Compose运行Docker镜像(模拟OpenShift(:

docker-compose up
docker-compose down
demo_demo_1 exited with code 137

当使用docker compose down停止应用程序时,将不会调用DisposableBean.default。

我怀疑Docker在发出SIGKILL之前正在尝试SIGTERM,因为在容器被杀死之前有10秒的延迟。

在许多地方设置可能出错。首先,我建议确定java/spring部分是否存在一些问题,或者它是与docker/环境相关的问题。从这个问题来看,它听起来像是与java相关的,但实际上我怀疑它不在java/spring中。

因此,mvn spring-boot:run按预期工作,并且我看到您将spring引导应用程序打包为jar(app.jar(,很可能带有spring引导插件。这也是一个可能出错的地方,因为spring-boot使用一个特殊的类加载器在运行时加载东西。

因此,为了完全消除"java/spring"部分,请导航到target目录并运行java -jar app.jar(当然,请确保本地机器上安装了java11(。如果不起作用,请调查java/spring部分,否则继续使用docker部分。

应用程序很可能会按预期运行。

现在,关于docker设置。在运行docker compose并看到它失败后,

您可以使用以下命令:

docker ps -a // -a flag to see container ids of containers that were stopped for whatever reason as well.

现在找到退出的java进程的Id并检查其日志:

docker logs <ID_OF_THE_EXTED_CONTAINER_GOES_HERE> 

现在,应用程序上下文可能无法启动(可能是网络相关的问题或其他什么,在这里,如果没有看到实际的日志,很难判断(,从而导致问题。

另一个可能的问题是应用程序"太重"(我的意思是它超过了码头集装箱的一些配额(。

您可以运行docker stats <CONTAINER_ID>命令来实时查看其内存/cpu使用情况,或者从应用程序中收集指标。

我想我找到了解决方案(在这个博客条目中(:在Dockerfile中使用exec形式而不是shell形式,这样Docker发出的SIGTERM就会到达java进程而不是bash进程(它不会向任何子进程转发信号(。

  • 外壳形式(使用/bin/sh-c外壳执行(:ENTRYPOINT java -jar /app.jar
  • Exec表单(在没有shell的情况下执行(:ENTRYPOINT ["java", "-jar", "/app.jar"]

最新更新