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