web-dev-qa-db-fra.com

Cycle de vie des haricots dans Spring Boot 2.1 et Java 11

Mon projet passe de Spring Boot 2.0.4 avec Java 8 à Spring Boot 2.1.0 avec Java 11. Lorsque l'application a été créée avec Spring Boot 2.0.4 et Java 8 et exécutée dans Docker/Docker Compose, la méthode annotée @PostConstruct- a été appelée, mais après le passage à Spring Boot 2.1.0 et à Java 11, la méthode annotée @PreDestroy-n'est plus appelée.

J'ai essayé de passer d'annotations à l'implémentation de InitializingBean et DisposableBean comme décrit ici , mais la méthode DisposableBean.destroy n'est pas appelée.

J'ai également essayé d'ajouter une dépendance à la version 1.3.2 de javax.annotation-api, avec le même résultat.

Comment reproduire:

Créez une application Spring minimale avec un bean lifecycle:

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");
    }
}

Démarrez l'application Spring à partir du sous-dossier cible:

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

Lorsque l'application est arrêtée à l'aide de Ctrl + C, le fichier DisposableBean.destroy est appelé.

Retournez dans le dossier parent:

cd ..

Démarrez l'application Spring à l'aide de Maven:

mvn spring-boot:run

Lorsque l'application est arrêtée à l'aide de Ctrl + C, le fichier DisposableBean.destroy est appelé.

Dockerfile:

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

Générez, exécutez et arrêtez l'image Docker:

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

Lorsque l'application est arrêtée à l'aide de docker stop, le fichier DisposableBean.destroy n'est pas appelé.

docker-compose.yml:

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

Exécuter l'image Docker à l'aide de Docker Compose (en simulant OpenShift):

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

Lorsque l'application est arrêtée avec Docker-Composer Down, le fichier DisposableBean.destroy n'est pas appelé.

Je soupçonne que Docker essaie un SIGTERM avant d’émettre un SIGKILL, car il faut 10 secondes pour que le conteneur soit tué.

4

Je pense avoir trouvé la solution (dans cette entrée de blog ): utiliser le formulaire exec au lieu du formulaire shell dans le fichier Docker pour que le SIGTERM que Docker émet frappe le processus Java au lieu du processus bash à tout processus enfant).

  • Formulaire Shell (exécuté avec un shell/bin/sh -c): ENTRYPOINT Java -jar /app.jar
  • Formulaire d'exécution (exécuté sans shell): ENTRYPOINT ["Java", "-jar", "/app.jar"]
1

Il existe de nombreux endroits où la configuration peut mal se passer .. Tout d’abord, je suggère d’identifier si Java/spring partie présente des problèmes ou si c’est un problème lié au menu fixe/environnement. De la question, cela ressemble à son Java, mais en réalité, je soupçonne que ce n’est pas Java/Spring.

Donc, mvn spring-boot:run fonctionne comme prévu et je vois que vous empaquetez l’application Spring Boot sous la forme de jar (app.jar), probablement avec un plugin Spring Boot. C'est également un endroit où les choses peuvent potentiellement mal tourner, car Spring Boot utilise un chargeur de classes spécial pour charger les choses en cours d'exécution. 

Donc, pour éliminer complètement la partie "Java/spring", allez dans votre répertoire target et exécutez Java -jar app.jar (assurez-vous que Java 11 est bien sûr installé sur votre ordinateur local). Si cela ne fonctionne pas - examinez la partie Java/spring, sinon passez à la partie fixe.

Les chances sont que l'application fonctionnera comme prévu.

Maintenant, comme pour l'installation de docker. Après avoir exécuté docker compose et constaté que cela échoue, 

Vous pouvez utiliser les commandes suivantes:

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

Maintenant, trouvez l’ID du processus Java qui s’est terminé et examinez ses journaux:

docker logs <ID_OF_THE_EXTED_CONTAINER_GOES_HERE> 

Il est maintenant probable que le contexte de l'application ne démarre pas (peut-être un problème lié au réseau ou quelque chose du genre, il est vraiment difficile de le savoir sans afficher un journal) et par conséquent le problème.

Un autre problème possible est que l'application est "trop ​​lourde" (j'entends par là qu'elle dépasse certains quotas imposés au conteneur docker).

Vous pouvez exécuter la commande docker stats <CONTAINER_ID> pour voir son utilisation de la mémoire/du processeur en temps réel ou rassembler des métriques à partir de l'application. 

1
Mark Bramnik