SpringApplicationContext-资源泄漏: “ context”永远不会关闭

在一个春季 MVC 应用程序中,我使用以下方法在一个服务类中初始化一个变量:

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

UserLibrary 是我在应用程序中使用的第三方实用程序。上面的代码为“ context”变量生成一个警告。警告如下:

Resource leak: 'context' is never closed

我不明白这警告是什么意思。由于应用程序是一个 Spring MVC 应用程序,因此在应用程序运行时引用服务时,我不能真正关闭/破坏上下文。这个警告到底想告诉我什么?

86961 次浏览

Since the app context is a ResourceLoader (i.e. I/O operations) it consumes resources that need to be freed at some point. It is also an extension of AbstractApplicationContext which implements Closable. Thus, it's got a close() method and can be used in a try-with-resources statement.

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

Whether you actually need to create this context is a different question (you linked to it), I'm not gonna comment on that.

It's true that the context is closed implicitly when the application is stopped but that's not good enough. Eclipse is right, you need to take measures to close it manually for other cases in order to avoid classloader leaks.

close() is not defined in ApplicationContext interface.

The only way to get rid of the warning safely is the following

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

Or, in Java 7

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

The basic difference is that since you instantiate the context explicitly (i.e. by use of new) you know the class you are instantiating, so you can define your variable accordingly.

If you were not instantiating the AppContext (i.e. using the one provided by Spring) then you couldn't close it.

try this. you need to apply cast to close applicationcontext.

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

Even I had the exact same warning, all I did was declare ApplicationContext outside the main function as private static and ta-da, problem fixed.

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

A simple cast solves the issue:

((ClassPathXmlApplicationContext) fac).close();

Downcast the context to ConfigurableApplicationContext.

((ConfigurableApplicationContext)context).close();

As the Application context has an instance of ClassPathXmlApplicationContext and the same has a close() method. I would simply CAST the appContext object and invoke the close() method as below.

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

This will fix the Resource Leak warning.

The method close has been added to ConfigurableApplicationContext interface, so the best you can do to get access to it is:

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


// Use the context...


context.close();

If you are using the ClassPathXmlApplicationContext then you can use

((ClassPathXmlApplicationContext) context).close();

to close the resource leak problem.

If you are using the AbstractApplicationContext then you can cast this with close method.

((AbstractApplicationContext) context).close();

It depends on the type of context using in the application.

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

In my case leak disappears

import org.springframework.context.ConfigurableApplicationContext;


((ConfigurableApplicationContext)ctx).close();

You make the context a static variable, which means that the context is available to all the static methods in the class, and not limited to the scope of the main method anymore. So the tool can't assume that it should be closed at the end of the method anymore, so it doesn't issue the warning anymore.

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();


}
}

Yes, interface ApplicationContext doesn't have close() method, so I like to use class AbstractApplicationContext to use that close method explicitly and also here you can use your Spring Application configuration class using annotation instead of XML type.

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


//do some work with foo


context.close();

your Resource leak: 'context' is never closed warning is gone now.

This worked out best for me.

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

Casting is the correct resolution for this issue. I faced the same issue using the below line. ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

To resolve the warning just downcast the ctx object like below and then close it. ((AnnotationConfigApplicationContext) ctx).close();

it has a simple solution just input the Core jar into the libraries, given at this link [download the core jar files for spring][1] [1]: https://static.javatpoint.com/src/sp/spcorejars.zip

for ApplicationContext you can't use close() method because this method doesn't define int it but instead you can use:(ClassPathXmlApplicationContext(context)).close()