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?
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.
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.
Un simple casting résout le problème:
((ClassPathXmlApplicationContext) fac).close();
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.
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();
}
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();
}
}
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();
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());
}
}
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 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();
}
}
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.
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();
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.