Spring ApplicationContext – Fuite de ressources: le contexte 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 bibliothèque utilisateur 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 lorsque 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?

Étant donné que le contexte de l’application est un ResourceLoader (c’est-à-dire des opérations d’E / S), il consum des ressources qui doivent être libérées à un moment donné. C’est aussi une extension de AbstractApplicationContext qui implémente Closable . Ainsi, il a une méthode close() et peut être utilisée dans une instruction try-with-resources .

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

Que vous ayez réellement besoin de créer ce contexte est une question différente (vous y avez lié), je ne vais pas commenter cela.

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 d’autres cas afin d’éviter les fuites de classloader.

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

La seule façon de se débarrasser de l’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 explicitement le contexte (c’est-à-dire en utilisant de 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 en utilisant celui fourni par Spring), vous ne pouviez pas le fermer.

Une simple dissortingbution résout le problème:

 ((ClassPathXmlApplicationContext) fac).close(); 

Comme le contexte d’application a une instance de ClassPathXmlApplicationContext et que la même chose a une méthode close (). Je ferais simplement CAST l’object 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.

essaye ça. vous devez appliquer la conversion pour fermer applicationcontext.

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

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

 public class MainApp { private static ApplicationContext context; public static void main(Ssortingng[] 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(); } } 

Abaisser le contexte à ConfigurableApplicationContext.

 ((ConfigurableApplicationContext)context).close(); 
 Object obj = context.getBean("bean"); if(bean instanceof Bean) { Bean bean = (Bean) obj; } 

Dans mon cas, la fuite disparaît

Si vous utilisez ClassPathXmlApplicationContext, vous pouvez utiliser

 ((ClassPathXmlApplicationContext) context).close(); 

pour résoudre le problème de fuite de ressources.

Si vous utilisez le AbstractApplicationContext, vous pouvez le lancer avec la méthode close.

 ((AbstractApplicationContext) context).close(); 

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

 import org.springframework.context.ConfigurableApplicationContext; ((ConfigurableApplicationContext)ctx).close(); 

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 ne se limite plus à la scope 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(Ssortingng[] args) { context = new ClassPathXmlApplicationContext("Beans.xml"); HelloWorld obj = (HelloWorld) context.getBean("helloWorld"); obj.getMessage(); } } 

Oui, l’interface ApplicationContext n’a pas de méthode close() , donc j’aime utiliser la classe AbstractApplicationContext pour utiliser explicitement cette méthode close et vous pouvez également utiliser votre classe de configuration Spring Application à l’aide d’annotations plutôt que de type XML .

 AbstractApplicationContext context = new AnnotationConfigApplicationContext(SpringAppConfig.class); Foo foo = context.getBean(Foo.class); //do some work with foo context.close(); 

votre Resource leak: 'context' is never closed

Cela a fonctionné le 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(Ssortingng[] 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()); } } 

La méthode close a été ajoutée à l’interface ConfigurableApplicationContext, alors le mieux que vous puissiez faire pour y accéder est la suivante:

 ConfigurableApplicationContext context = new ClassPathXmlApplicationContext( "/app-context.xml"); // Use the context... context.close();