webentwicklung-frage-antwort-db.com.de

Spring ApplicationContext - Ressourcenleck: 'context' wird nie geschlossen

In einer Spring-MVC-Anwendung initialisiere ich eine Variable in einer der Serviceklassen unter Verwendung des folgenden Ansatzes:

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

Die UserLibrary ist ein Dienstprogramm von Drittanbietern, das ich in meiner Anwendung verwende. Der obige Code generiert eine Warnung für die Variable 'context'. Die Warnung wird unten angezeigt:

Resource leak: 'context' is never closed

Ich verstehe die Warnung nicht. Da es sich bei der Anwendung um eine Spring-MVC-Anwendung handelt, kann ich den Kontext nicht wirklich schließen/zerstören, da ich auf den Dienst verweise, während die Anwendung ausgeführt wird. Was genau versucht die Warnung mir zu sagen?

83
ziggy

Da der App-Kontext eine ResourceLoader (d. H. E/A-Operationen) ist, verbraucht er Ressourcen, die an einem bestimmten Punkt freigegeben werden müssen. Es ist auch eine Erweiterung von AbstractApplicationContext, die Closable implementiert. Daher hat es eine close()-Methode und kann in einer try-with-resources-Anweisung verwendet werden.

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

Ob Sie diesen Kontext wirklich erstellen müssen, ist eine andere Frage (Sie haben damit verlinkt), ich werde das nicht kommentieren.

Es stimmt, dass der Kontext implizit geschlossen wird, wenn die Anwendung angehalten wird. Dies ist jedoch nicht gut genug. Eclipse hat Recht, Sie müssen Maßnahmen ergreifen, um es für andere Fälle manuell zu schließen, um Lecks des Klassenladers zu vermeiden.

81
Marcel Stör

close() ist in der ApplicationContext-Schnittstelle nicht definiert.

Die einzige Möglichkeit, die Warnung sicher loszuwerden, ist die folgende

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

Oder in Java 7

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

Der grundlegende Unterschied besteht darin, dass Sie den Kontext explizit instanziieren (d. H. Durch Verwendung von new), dass Sie die Klasse kennen, die Sie instanziieren, sodass Sie Ihre Variable entsprechend definieren können.

Wenn Sie den AppContext nicht instanziiert haben (d. H. Den von Spring bereitgestellten), konnten Sie ihn nicht schließen.

Eine einfache Besetzung löst das Problem:

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

Da der Anwendungskontext über eine Instanz von ClassPathXmlApplicationContext verfügt und dieselbe über eine close () - Methode verfügt Ich würde einfach das appContext-Objekt CAST und die close () -Methode wie folgt aufrufen.

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

Dadurch wird die Warnung zum Ressourcenleck behoben.

6

versuche dies. Sie müssen cast anwenden, um den Anwendungskontext zu schließen. 

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

Selbst wenn ich genau dieselbe Warnung hatte, erklärte ich nur ApplicationContext außerhalb der Hauptfunktion als private static und ta-da. Problem wurde behoben.

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

In meinem Fall verschwindet das Leck

Übertragen Sie den Kontext an ConfigurableApplicationContext.

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

Das hat für mich am besten funktioniert.

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

Sie machen den Kontext zu einer statischen Variablen. Das bedeutet, dass der Kontext für alle statischen Methoden in der Klasse verfügbar ist und nicht mehr auf den Geltungsbereich der Hauptmethode beschränkt ist. Das Tool kann daher nicht mehr davon ausgehen, dass es am Ende der Methode geschlossen werden sollte, und gibt daher keine Warnung mehr aus.

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

Wenn Sie ClassPathXmlApplicationContext verwenden, können Sie dies verwenden 

((ClassPathXmlApplicationContext) context).close();

um das Ressourcenleckproblem zu schließen.

Wenn Sie AbstractApplicationContext verwenden, können Sie dies mit der close-Methode umsetzen.

((AbstractApplicationContext) context).close();

Dies hängt von der Art des Kontextes ab, der in der Anwendung verwendet wird.

0
Laxman Edara

Casting ist die richtige Lösung für dieses Problem. Ich habe das gleiche Problem mit der folgenden Zeile konfrontiert. ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

Um die Warnung zu beheben, streichen Sie das Objekt ctx wie unten beschrieben herunter und schließen Sie es dann. ((AnnotationConfigApplicationContext) ctx).close();

0
Aadi

Ja, die Schnittstelle ApplicationContext hat keine close()-Methode. Daher benutze ich gerne die Klasse AbstractApplicationContext, um diese close-Methode explizit zu verwenden. Hier können Sie auch die Spring Application-Konfigurationsklasse mit Annotation anstelle von XML verwenden.

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

//do some work with foo

context.close();

ihre Resource leak: 'context' is never closed-Warnung ist jetzt weg.

0
ArifMustafa