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アプリケーションなので、アプリケーションの実行中にサービスを参照するため、コンテキストを実際に閉じたり破棄したりすることはできません。警告は私に何を伝えようとしているのですか?
アプリのコンテキストは ResourceLoader
(つまりI/O操作)であるため、ある時点で解放する必要があるリソースを消費します。また、AbstractApplicationContext
を実装するClosable
の拡張機能です。したがって、close()
メソッドがあり、 try-with-resourcesステートメント で使用できます。
try (ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/userLibrary.xml")) {
service = context.getBean(UserLibrary.class);
}
このコンテキストを実際に作成する必要があるかどうかは別の質問です(リンクしている)が、それについてはコメントしません。
アプリケーションが停止するとコンテキストが暗黙的に閉じられるのは事実ですが、それだけでは十分ではありません。 Eclipseは正しいので、クラスローダーのリークを回避するために、他の場合は手動で閉じる手段を講じる必要があります。
close()
はApplicationContext
インターフェイスで定義されていません。
警告を安全に取り除く唯一の方法は次のとおりです
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(...);
try {
[...]
} finally {
ctx.close();
}
または、Java 7で
try(ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(...)) {
[...]
}
基本的な違いは、コンテキストを明示的にインスタンス化する(つまりnew
を使用する)ため、インスタンス化するクラスがわかっているため、それに応じて変数を定義できることです。
AppContextをインスタンス化していない場合(つまり、Springが提供するものを使用している場合)、閉じることができませんでした。
単純なキャストで問題を解決します。
((ClassPathXmlApplicationContext) fac).close();
ApplicationコンテキストにはClassPathXmlApplicationContextのインスタンスがあり、同じコンテキストにはclose()メソッドがあります。私は単にappContextオブジェクトをキャストし、以下のようにclose()メソッドを呼び出します。
ApplicationContext appContext = new ClassPathXmlApplicationContext("spring.xml");
//do some logic
((ClassPathXmlApplicationContext) appContext).close();
これにより、リソースリークの警告が修正されます。
これを試して。 applicationcontextを閉じるにはキャストを適用する必要があります。
ClassPathXmlApplicationContext ctx = null;
try {
ctx = new ClassPathXmlApplicationContext(...);
[...]
} finally {
if (ctx != null)
((AbstractApplicationContext) ctx).close();
}
まったく同じ警告が表示された場合でも、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();
}
}
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());
}
}
キャストは、この問題の正しい解決策です。私は以下の行を使用して同じ問題に直面しました。 ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
警告を解決するには、以下のようにctx
オブジェクトをダウンキャストしてから閉じます。 ((AnnotationConfigApplicationContext) ctx).close();
コンテキストをConfigurableApplicationContextにダウンキャストします。
((ConfigurableApplicationContext)context).close();
import org.springframework.context.ConfigurableApplicationContext;
((ConfigurableApplicationContext)ctx).close();
コンテキストを静的変数にします。つまり、コンテキストはクラス内のすべての静的メソッドで使用でき、メインメソッドのスコープに制限されなくなります。そのため、ツールはメソッドの最後で閉じる必要があると想定できないため、警告は発行されません。
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();
}
}
ClassPathXmlApplicationContextを使用している場合は、次を使用できます。
((ClassPathXmlApplicationContext) context).close();
リソースリークの問題を解決します。
AbstractApplicationContextを使用している場合は、closeメソッドでこれをキャストできます。
((AbstractApplicationContext) context).close();
アプリケーションで使用しているコンテキストのタイプに依存します。
はい、インターフェイス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
警告はなくなりました。