98

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

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

UserLibrary 是我在我的应用程序中使用的第 3 方实用程序。上面的代码为 'context' 变量生成警告。警告如下所示:

Resource leak: 'context' is never closed

我不明白这个警告。由于该应用程序是 Spring MVC 应用程序,因此在应用程序运行时引用服务时,我无法真正关闭/销毁上下文。警告到底想告诉我什么?

4

17 回答 17

95

由于应用程序上下文是一个ResourceLoader(即 I/O 操作),它消耗需要在某个时候释放的资源。它也是AbstractApplicationContextwhich implements的扩展Closable。因此,它有一个close()方法,可以在try-with-resources 语句中使用

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

你是否真的需要创建这个上下文是一个不同的问题(你链接到它),我不会对此发表评论。

确实,当应用程序停止时,上下文会隐式关闭,但这还不够好。Eclipse是对的,其他情况需要采取措施手动关闭,避免classloader泄漏。

于 2013-01-06T22:21:53.117 回答
40

close()接口中没有定义ApplicationContext

安全摆脱警告的唯一方法是以下

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

或者,在 Java 7 中

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

基本区别在于,由于您显式实例化上下文(即通过使用new),您知道要实例化的类,因此您可以相应地定义变量。

如果您没有实例化 AppContext(即使用 Spring 提供的那个),那么您将无法关闭它。

于 2013-02-12T10:16:00.153 回答
14

一个简单的演员表解决了这个问题:

((ClassPathXmlApplicationContext) fac).close();
于 2014-03-19T17:48:54.213 回答
7

由于 Application 上下文有一个 ClassPathXmlApplicationContext 的实例,并且同样有一个 close() 方法。我只需 CAST appContext 对象并调用 close() 方法,如下所示。

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

这将修复资源泄漏警告。

于 2015-01-09T13:40:20.673 回答
4

试试这个。您需要应用强制转换来关闭应用程序上下文。

   ClassPathXmlApplicationContext ctx = null;
      try {
         ctx = new ClassPathXmlApplicationContext(...);
            [...]
             } finally {
              if (ctx != null)
                  ((AbstractApplicationContext) ctx).close();       
      }
于 2013-08-04T06:07:01.227 回答
3

即使我有完全相同的警告,我所做的只是ApplicationContext在主函数之外声明为private static和 ta-da,问题已修复。

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();
    }
}
于 2014-03-13T05:34:35.997 回答
2

强制转换是解决此问题的正确方法。我使用下面的行遇到了同样的问题。 ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

要解决警告,只需ctx像下面一样向下转换对象,然后关闭它。 ((AnnotationConfigApplicationContext) ctx).close();

于 2019-03-22T18:59:33.227 回答
1

将上下文向下转换为 ConfigurableApplicationContext。

((ConfigurableApplicationContext)context).close();
于 2014-08-07T09:26:37.960 回答
1
Object obj = context.getBean("bean");
if(bean instanceof Bean) {
    Bean bean = (Bean) obj;
}

就我而言,泄漏消失了

于 2016-04-20T11:19:05.653 回答
1

这对我来说效果最好。

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());
    }
}
于 2018-04-23T16:14:38.583 回答
0

如果您使用的是ClassPathXmlApplicationContext那么您可以使用

((ClassPathXmlApplicationContext) context).close();

关闭资源泄漏问题。

如果您使用的是AbstractApplicationContext,那么您可以使用 close 方法进行转换。

((AbstractApplicationContext) context).close();

这取决于应用程序中使用的上下文类型。

于 2015-08-09T21:05:37.917 回答
0
import org.springframework.context.ConfigurableApplicationContext;

((ConfigurableApplicationContext)ctx).close();
于 2016-10-02T09:59:27.743 回答
0

您将上下文设置为静态变量,这意味着该上下文可用于类中的所有静态方法,并且不再局限于 main 方法的范围。因此该工具不能再假定它应该在方法结束时关闭,因此它不再发出警告。

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

       }
}
于 2017-01-30T18:45:05.960 回答
0

是的,接口ApplicationContext没有close()方法,所以我喜欢使用类AbstractApplicationContext来显式使用该close方法,并且在这里您可以使用注释而不是XML类型来使用 Spring Application 配置类。

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警告现在消失了。

于 2018-01-30T08:20:57.047 回答
0

它有一个简单的解决方案,只需将核心 jar 输入到库中,在此链接中给出 [下载 spring 的核心 jar 文件][1] [1]:https://static.javatpoint.com/src/sp/spcorejars。压缩

于 2020-06-25T10:50:58.223 回答
0

对于 ApplicationContext 你不能使用 close() 方法,因为这个方法没有定义它,而是你可以使用:(ClassPathXmlApplicationContext(context)).close()

于 2020-11-15T18:30:07.070 回答
-1

方法 close 已添加到 ConfigurableApplicationContext 接口中,因此您可以做的最好的访问是:

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

// Use the context...

context.close();
于 2015-04-22T18:50:52.273 回答