web-dev-qa-db-ja.com

Spring ApplicationContext-リソースリーク:「コンテキスト」が閉じられることはありません

Spring MVCアプリケーションでは、次のアプローチを使用して、サービスクラスの1つの変数を初期化します。

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

UserLibraryは、アプリケーションで使用しているサードパーティのユーティリティです。上記のコードは、「コンテキスト」変数に対して警告を生成します。警告は次のとおりです。

Resource leak: 'context' is never closed

警告がわかりません。アプリケーションはSpring MVCアプリケーションなので、アプリケーションの実行中にサービスを参照するため、コンテキストを実際に閉じたり破棄したりすることはできません。警告は私に何を伝えようとしているのですか?

90
ziggy

アプリのコンテキストは ResourceLoader (つまりI/O操作)であるため、ある時点で解放する必要があるリソースを消費します。また、AbstractApplicationContextを実装するClosableの拡張機能です。したがって、close()メソッドがあり、 try-with-resourcesステートメント で使用できます。

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

このコンテキストを実際に作成する必要があるかどうかは別の質問です(リンクしている)が、それについてはコメントしません。

アプリケーションが停止するとコンテキストが暗黙的に閉じられるのは事実ですが、それだけでは十分ではありません。 Eclipseは正しいので、クラスローダーのリークを回避するために、他の場合は手動で閉じる手段を講じる必要があります。

86
Marcel Stör

close()ApplicationContextインターフェイスで定義されていません。

警告を安全に取り除く唯一の方法は次のとおりです

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

または、Java 7で

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

基本的な違いは、コンテキストを明示的にインスタンス化する(つまりnewを使用する)ため、インスタンス化するクラスがわかっているため、それに応じて変数を定義できることです。

AppContextをインスタンス化していない場合(つまり、Springが提供するものを使用している場合)、閉じることができませんでした。

単純なキャストで問題を解決します。

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

ApplicationコンテキストにはClassPathXmlApplicationContextのインスタンスがあり、同じコンテキストにはclose()メソッドがあります。私は単にappContextオブジェクトをキャストし、以下のようにclose()メソッドを呼び出します。

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

これにより、リソースリークの警告が修正されます。

6

これを試して。 applicationcontextを閉じるにはキャストを適用する必要があります。

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

まったく同じ警告が表示された場合でも、private staticおよびta-daとしてメイン関数の外でApplicationContextを宣言するだけで問題は修正されました。

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

私の場合、リークは消えます

これは私にとって最もうまくいきました。

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());
    }
}
1
i4nk1t

キャストは、この問題の正しい解決策です。私は以下の行を使用して同じ問題に直面しました。 ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

警告を解決するには、以下のようにctxオブジェクトをダウンキャストしてから閉じます。 ((AnnotationConfigApplicationContext) ctx).close();

1
Aadi

コンテキストをConfigurableApplicationContextにダウンキャストします。

((ConfigurableApplicationContext)context).close();
1
amit28
import org.springframework.context.ConfigurableApplicationContext;

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

コンテキストを静的変数にします。つまり、コンテキストはクラス内のすべての静的メソッドで使用でき、メインメソッドのスコープに制限されなくなります。そのため、ツールはメソッドの最後で閉じる必要があると想定できないため、警告は発行されません。

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

ClassPathXmlApplicationContextを使用している場合は、次を使用できます。

((ClassPathXmlApplicationContext) context).close();

リソースリークの問題を解決します。

AbstractApplicationContextを使用している場合は、closeメソッドでこれをキャストできます。

((AbstractApplicationContext) context).close();

アプリケーションで使用しているコンテキストのタイプに依存します。

0
Laxman Edara

はい、インターフェイスApplicationContextにはclose()メソッドがありません。そのため、クラスAbstractApplicationContextを使用してそのcloseメソッドを明示的に使用し、ここでSpring Application構成を使用することもできますXML型の代わりに注釈を使用するクラス。

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

//do some work with foo

context.close();

Resource leak: 'context' is never closed警告はなくなりました。

0
ArifMustafa