Spring ApplicationContext – 资源泄漏:“context”永远不会closures

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

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

UserLibrary是我在我的应用程序中使用的第三方实用程序。 上面的代码会为“上下文”variables生成警告。 警告如下所示:

 Resource leak: 'context' is never closed 

我不明白这个警告。 由于应用程序是一个Spring MVC应用程序,因此当应用程序正在运行时,我不能真正closures/销毁上下文。 试图告诉我的警告究竟是什么?

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

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

无论你真的需要创build这个环境是一个不同的问题(你链接到它),我不会评论这一点。

确实,当应用程序停止时,上下文是隐式closures的,但这还不够好。 Eclipse是正确的,你需要采取措施手动closures其他情况,以避免类加载器泄漏。

close()没有在ApplicationContext接口中定义。

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

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

或者,在Java 7中

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

基本的区别是,因为你明确地实例化上下文(即使用new )你知道你正在实例化的类,所以你可以相应地定义你的variables。

如果你没有实例化AppContext(即使用Spring提供的那个),那么你不能closures它。

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

 ((ClassPathXmlApplicationContext) fac).close(); 

由于Application上下文具有ClassPathXmlApplicationContext的实例,并且具有close()方法。 我会简单地CAST的appContext对象,并调用close()方法如下。

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

这将修复资源泄漏警告。

即使我有完全相同的警告,我所做的只是在主函数之外声明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(); } } 

尝试这个。 您需要应用转换closures应用程序上下文。

  ClassPathXmlApplicationContext ctx = null; try { ctx = new ClassPathXmlApplicationContext(...); [...] } finally { if (ctx != null) ((AbstractApplicationContext) ctx).close(); } 
 Object obj = context.getBean("bean"); if(bean instanceof Bean) { Bean bean = (Bean) obj; } 

在我的情况下泄漏消失

将上下文下载到ConfigurableApplicationContext。

 ((ConfigurableApplicationContext)context).close(); 

如果你正在使用ClassPathXmlApplicationContext,那么你可以使用

 ((ClassPathXmlApplicationContext) context).close(); 

closures资源泄漏问题。

如果您正在使用AbstractApplicationContext,那么您可以使用close方法进行强制转换。

 ((AbstractApplicationContext) context).close(); 

这取决于在应用程序中使用的上下文的types。

 import org.springframework.context.ConfigurableApplicationContext; ((ConfigurableApplicationContext)ctx).close(); 

您将上下文设置为静态variables,这意味着该上下文对于该类中的所有静态方法都是可用的,而不再局限于主方法的范围。 因此,该工具不能假定它应该在方法结束时closures,因此不再发出警告。

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

close方法已经被添加到ConfigurableApplicationContext接口中,所以你可以做的最好的方法是访问它:

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