我的项目正在从带有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
-带注释的方式。
我已经尝试过从注释切换到实现这里描述的InitializingBean
和DisposableBean
,但没有调用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"]