web-dev-qa-db-fra.com

Spring ApplicationContext - Fuite de ressources: le "contexte" n'est jamais fermé

Dans une application MVC de printemps, j'initialise une variable dans l'une des classes de service à l'aide de l'approche suivante:

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

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 indiqué 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 est en cours d'exécution. Qu'est-ce que l'avertissement essaie de me dire exactement?

83
ziggy

Le contexte de l'application étant une ResourceLoader (c'est-à-dire des opérations d'E/S), il consomme des ressources qui doivent être libérées à un moment donné. C'est également une extension de AbstractApplicationContext qui implémente Closable. Ainsi, il possède une méthode close() et peut être utilisé dans une instruction try-with-resources .

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

Si vous avez réellement besoin de créer ce contexte est une question différente (vous y êtes lié), je ne ferai pas de commentaire à ce sujet.

Il est vrai que le contexte est fermé implicitement lorsque l'application est arrêtée, mais cela ne suffit pas. Eclipse a raison, vous devez prendre des mesures pour le fermer manuellement dans d’autres cas afin d’éviter les fuites du chargeur de classe.

81
Marcel Stör

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

Le seul moyen de se débarrasser de l'avertissement en toute sécurité est le suivant

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 explicitement le contexte (c'est-à-dire en utilisant new), vous connaissez la classe que vous instanciez, vous pouvez donc définir votre variable en conséquence.

Si vous n’instanciez pas AppContext (c’est-à-dire celui fourni par Spring), vous ne pourriez pas le fermer.

38

Un simple casting résout le problème:

((ClassPathXmlApplicationContext) fac).close();
11
RCInd

Comme le contexte d'application a une instance de ClassPathXmlApplicationContext et que celle-ci a une méthode close (). Je voudrais simplement CAST l'objet appContext et invoquer la méthode close () comme ci-dessous.

ApplicationContext appContext = new ClassPathXmlApplicationContext("spring.xml");
//do some logic
((ClassPathXmlApplicationContext) appContext).close();

Cela corrigera l'avertissement de fuite de ressource.

6
Ashutosh Srivastav

essaye ça. vous devez appliquer la conversion pour fermer le contexte d'application. 

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

Même si j'avais le même avertissement, tout ce que je faisais était de déclarer ApplicationContext en dehors de la fonction principale en tant que private static et ta-da, le problème était résolu.

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();
    }
}
3
Elysium
Object obj = context.getBean("bean");
if(bean instanceof Bean) {
    Bean bean = (Bean) obj;
}

Dans mon cas, la fuite disparaît

Downcast le contexte à ConfigurableApplicationContext.

((ConfigurableApplicationContext)context).close();
1
amit28

Cela a fonctionné mieux pour moi.

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class Test {

     private static ApplicationContext con;

     public static void main(String[] args) {

         con = new ClassPathXmlApplicationContext("config.xml");

         Employee ob = (Employee) con.getBean("obj");
         System.out.println("Emp Id " + ob.getEmpno());
         System.out.println("Emp name " + ob.getEmpname());
    }
}
0
i4nk1t
import org.springframework.context.ConfigurableApplicationContext;

((ConfigurableApplicationContext)ctx).close();
0
Yao Pan

Vous faites du contexte une variable statique, ce qui signifie que le contexte est disponible pour toutes les méthodes statiques de la classe et n'est plus limité à la portée de la méthode principale. Donc, l'outil ne peut plus supposer qu'il devrait être fermé à la fin de la méthode, donc il ne lance plus l'avertissement.

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

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

          obj.getMessage();

       }
}
0
Nanhe Kumar

Si vous utilisez le ClassPathXmlApplicationContext alors vous pouvez utiliser 

((ClassPathXmlApplicationContext) context).close();

fermer le problème de fuite de ressources.

Si vous utilisez AbstractApplicationContext , vous pouvez convertir ceci avec la méthode close.

((AbstractApplicationContext) context).close();

Cela dépend du type de contexte utilisé dans l'application.

0
Laxman Edara

Le casting est la résolution correcte pour ce problème. J'ai fait face au même problème en utilisant la ligne ci-dessous. ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

Pour résoudre l'avertissement, descendez simplement l'objet ctx comme ci-dessous, puis fermez-le. ((AnnotationConfigApplicationContext) ctx).close();

0
Aadi

Oui, l'interface ApplicationContext n'a pas de méthode close(); j'aime donc utiliser la classe AbstractApplicationContext pour utiliser cette méthode close de manière explicite. Vous pouvez également utiliser ici votre classe de configuration Spring Application en utilisant une annotation au lieu du type XML.

AbstractApplicationContext context = new AnnotationConfigApplicationContext(SpringAppConfig.class);
Foo foo = context.getBean(Foo.class);

//do some work with foo

context.close();

votre avertissement Resource leak: 'context' is never closed est parti maintenant.

0
ArifMustafa