101 votes

Spring ApplicationContext - Fuite de ressources : 'context' n'est jamais fermé

Dans une application spring MVC, j'initialise une variable dans l'une des classes de service en utilisant l'approche suivante :

ApplicationContext context = 
         new ClassPathXmlApplicationContext("META-INF/userLibrary.xml");
service = context.getBean(UserLibrary.class);

La UserLibrary est un utilitaire tiers que j'utilise dans mon application. Le code ci-dessus génère un avertissement pour la variable 'context'. L'avertissement est présenté ci-dessous :

Resource leak: 'context' is never closed

Je ne comprends pas l'avertissement. Comme l'application est une application Spring MVC, je ne peux pas vraiment fermer/détruire le contexte car je me réfère au service pendant que l'application fonctionne. Qu'est-ce que l'avertissement essaie de me dire exactement ?

2 votes

Je suis curieux de savoir pourquoi vous créez un autre contexte d'application plutôt que de créer le bean dans le contexte d'application bootstrapé par Spring MVC.

0 votes

Voir ce fil stackoverflow.com/questions/14184177/ pour une explication sur la raison pour laquelle j'ai dû créer un nouveau conteneur.

0 votes

Quand est-ce que ce déclin est montré : pendant que vous créez le contexte ?

96voto

Marcel Stör Points 5458

Puisque le contexte de l'application est un ResourceLoader (c'est-à-dire les opérations d'E/S), il consomme des ressources qui doivent être libérées à un moment donné. Il s'agit également d'une extension de AbstractApplicationContext qui met en œuvre Closable . Ainsi, il a un close() et peut être utilisé dans une déclaration d'essai avec les ressources .

try (ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/userLibrary.xml")) {
  service = context.getBean(UserLibrary.class);
}

La question de savoir si vous avez réellement besoin de créer ce contexte est différente (vous y avez fait un lien), je ne vais pas me prononcer sur ce point.

Il est vrai que le contexte est fermé implicitement lorsque l'application est arrêtée, mais ce n'est pas suffisant. Eclipse a raison, vous devez prendre des mesures pour le fermer manuellement pour les autres cas afin d'éviter les fuites de classloader.

0 votes

Je pense que la source du problème est en fait le fait que je crée un contexte différent. Supprimer ce contexte supplémentaire est probablement une meilleure option que d'essayer de résoudre l'avertissement. Merci.

26 votes

A noter : alors que la base ApplicationContext ne fournit pas l'interface close() méthode, ConfigurableApplicationContext (qui ClassPathXmlApplicationContext met en œuvre) fait et étend Closeable pour démarrer, afin de pouvoir utiliser le paradigme "try-with-resource" de Java 7.

0 votes

@kbolino. L'instruction try-with-resources garantit que chaque ressource est fermée à la fin de l'instruction.

40voto

djechelon Points 8092

close() n'est pas défini dans ApplicationContext interface.

La seule façon de se débarrasser de cet avertissement en toute sécurité est la suivante

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(...);
try {
    [...]
} finally {
    ctx.close();
}

Ou, en Java 7

try(ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(...)) {
    [...]
}

La différence fondamentale est que, puisque vous instanciez le contexte de manière explicite (c'est-à-dire en utilisant l'option new ) vous connaissez la classe que vous instanciez, vous pouvez donc définir votre variable en conséquence.

Si vous n'instanciez pas l'AppContext (c'est-à-dire si vous utilisez celui fourni par Spring), vous ne pouviez pas le fermer.

6 votes

Encore et encore, le mauvais essai... est finalement enseigné aux autres... Le site new ClassPathXmlApplicationContext(...); doit être en dehors du bloc d'essai. Dans ce cas, la vérification de la nullité n'est pas nécessaire. Si le constructeur lève une exception, alors ctx est nul et le finally n'est pas appelé (parce que l'exception a été levée en dehors du bloc d'essai). Si le constructeur n'a pas levé d'exception, alors le bloc try est entré et ctx ne peut pas être nulle, il n'y a donc pas besoin de vérifier si elle est nulle.

0 votes

Cette réponse est mauvaise, il y a un réel problème avec votre bloc try finally. Je viens de le tester mais il ne fonctionne pas du tout.

15voto

RCInd Points 31

Un simple moulage résout le problème :

((ClassPathXmlApplicationContext) fac).close();

4voto

madhureddy480 Points 39

Essayez ceci. Vous devez appliquer le cast pour fermer l'applicationcontext.

   ClassPathXmlApplicationContext ctx = null;
      try {
         ctx = new ClassPathXmlApplicationContext(...);
            [...]
             } finally {
              if (ctx != null)
                  ((AbstractApplicationContext) ctx).close();       
      }

3voto

Elysium Points 97

Même si j'ai eu exactement le même avertissement, je n'ai fait que déclarer ApplicationContext en dehors de la fonction principale comme private static et ta-da, problème réglé.

public class MainApp {
    private static ApplicationContext context;

    public static void main(String[] args) {
        context = new ClassPathXmlApplicationContext("Beans.xml");

        HelloWorld objA = (HelloWorld) context.getBean("helloWorld");

        objA.setMessage("I'm object A");
        objA.getMessage();

        HelloWorld objB = (HelloWorld) context.getBean("helloWorld");
        objB.getMessage();
    }
}

11 votes

Cela résout le problème de l'avertissement mais pas le vrai problème qui est de laisser le contexte ouvert et de provoquer une fuite. Vous pourriez faire la même chose avec un @SupressWarnings annotation, mais c'est toujours mieux de résoudre le problème de la racine, ne pensez-vous pas ?

1 votes

Oui, vous avez raison c'était juste une solution de rechange pour moi à ce moment-là.

0 votes

Ce n'est pas une bonne réponse, puisque le problème réel reste le même, c'est-à-dire qu'il y a une fuite de ressources, le contexte n'est jamais fermé.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X