java - 예제 - 스프링 라이브러리




Spring ApplicationContext-리소스 누출:'context'는 절대로 닫히지 않습니다. (10)

스프링 MVC 애플리케이션에서 다음 접근법을 사용하여 서비스 클래스 중 하나에서 변수를 초기화한다.

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

UserLibrary는 제 응용 프로그램에서 사용하는 타사 유틸리티입니다. 위의 코드는 'context'변수에 대한 경고를 생성합니다. 경고는 아래와 같습니다.

Resource leak: 'context' is never closed

나는 경고를 이해하지 못한다. 응용 프로그램은 Spring MVC 응용 프로그램이므로 응용 프로그램이 실행되는 동안 서비스를 참조 할 때 문맥을 닫거나 닫을 수는 없습니다. 말해 주려고하는 경고가 정확히 무엇입니까?


close 메소드가 ConfigurableApplicationContext 인터페이스에 추가되었으므로 액세스 권한을 얻기 위해 최선을 다할 수 있습니다.

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

// Use the context...

context.close();

간단한 캐스트는이 문제를 해결합니다.

((ClassPathXmlApplicationContext) fac).close();

앱 컨텍스트가 ResourceLoader (예 : I / O 작업)이기 때문에 어느 시점에서 해제해야하는 리소스를 사용합니다. 또한 Closable 을 구현하는 AbstractApplicationContext 의 확장입니다. 따라서 close() 메서드가있어 try-with-resources 문 에서 사용할 수 있습니다.

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

실제로이 컨텍스트를 만들 필요가 있는지 여부는 다른 질문입니다 (연결된 경우). 나는 그것에 대해 언급하지 않을 것입니다.

응용 프로그램이 중지되었지만 충분히 좋지 않을 때 컨텍스트가 암시 적으로 닫히는 것은 사실입니다. 이클립스가 옳다면 클래스 로더 누수를 피하기 위해 다른 경우에 수동으로 닫아야한다.


예, interface ApplicationContext 에는 close() 메소드가 없으므로 AbstractApplicationContext 클래스를 사용하여 명시 적으로 close 메소드를 사용하고 XML 유형 대신 annotation을 사용하여 스프링 애플리케이션 구성 클래스를 사용할 수 있습니다.

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 . 경고가 사라졌습니다.


이 시도. applicationcontext를 닫으려면 캐스트를 적용해야합니다.

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

이것은 나를 위해 최선을 다했다.

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

컨텍스트를 정적 변수로 만들면 컨텍스트가 더 이상 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();

       }
}

close()ApplicationContext 인터페이스에 정의되어 있지 않습니다.

경고를 안전하게 제거하는 유일한 방법은 다음과 같습니다.

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

또는 Java 7

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

기본 차이점은 명시 적으로 컨텍스트를 인스턴스화 (즉, new 를 사용)함으로써 인스턴스를 생성하는 클래스를 알 수 있으므로 그에 따라 변수를 정의 할 수 있다는 것입니다.

Spring이 제공 한 AppContext를 사용하여 AppContext를 인스턴스화하지 않았다면이를 닫을 수 없다.


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

내 경우에는 누수가 사라집니다.


import org.springframework.context.ConfigurableApplicationContext;

((ConfigurableApplicationContext)ctx).close();