Spring ApplicationContext-리소스 누출 : '컨텍스트'가 닫히지 않습니다.


94

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

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

UserLibrary는 내 응용 프로그램에서 사용중인 타사 유틸리티입니다. 위의 코드는 'context'변수에 대한 경고를 생성합니다. 경고는 다음과 같습니다.

Resource leak: 'context' is never closed

경고를 이해하지 못합니다. 애플리케이션이 Spring MVC 애플리케이션이기 때문에 애플리케이션이 실행되는 동안 서비스를 참조 할 때 컨텍스트를 실제로 닫거나 삭제할 수 없습니다. 나에게 알려 주려는 경고가 정확히 무엇입니까?


2
나는 스프링 MVC에 의해 부트 스트랩 응용 프로그램의 컨텍스트 내에서 빈 생성에 반대하는 이유는 다른 응용 프로그램 컨텍스트를 만드는에 궁금 해요
케빈 Bowersox

새 컨테이너를 만들어야하는 이유에 대한 설명 은이 스레드 stackoverflow.com/questions/14184177/… 을 참조하십시오 .
ziggy

이 약화는 언제 표시됩니까? 컨텍스트를 만드는 동안?
Ralph

나는 Eclipse에서만 보았다 (노란색 밑줄). 방금 응용 프로그램을 실행할 때 로그를 확인했지만 경고가 표시되지 않습니다.
ziggy

답변:


92

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

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

이 컨텍스트를 실제로 만들어야하는지 여부는 다른 질문 (연결된 질문 임)에 대해서는 언급하지 않겠습니다.

응용 프로그램이 중지되면 컨텍스트가 암시 적으로 닫히는 것은 사실이지만 충분하지 않습니다. Eclipse가 맞습니다. 클래스 로더 누출을 피하기 위해 다른 경우에 대해 수동으로 닫는 조치를 취해야합니다.


문제의 원인은 실제로 내가 다른 맥락을 창조했다는 사실이라고 생각합니다. 추가 컨텍스트를 제거하는 것이 경고를 해결하는 것보다 더 나은 옵션 일 수 있습니다. 감사.
ziggy

25
주목할만한 점 : 기본 ApplicationContext인터페이스는 close()메소드를 제공하지 않지만 ConfigurableApplicationContext( ClassPathXmlApplicationContext구현하는) Closeable부팅을 수행하고 확장 하므로 Java 7 try-with-resource 패러다임을 사용할 수 있습니다.
kbolino 2013

@kbolino. try-with-resources 문은 문 끝에서 각 리소스가 닫히도록합니다.
ruruskyi


3
여기 @kbolino의 의견에 +1, 왜냐하면 내 변수를로 선언하고 ApplicationContext사용 가능한 가까운 방법이없는 것처럼
보였을

40

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

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

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

또는 Java 7에서

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

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

AppContext를 인스턴스화하지 않았다면 (즉, Spring에서 제공하는 것을 사용) 닫을 수 없습니다.


6
계속해서 잘못된 시도 ... 마지막으로 다른 사람들에게 가르쳐집니다 ... new ClassPathXmlApplicationContext(...);시도 블록 밖에 있어야합니다. 그러면 널 검사가 필요하지 않습니다. 생성자가 예외를 throw하면 ctxnull이고 finally블록이 호출되지 않습니다 (예외가 try- 블록 외부에서 throw 되었기 때문). 생성자가 예외를 throw하지 않은 경우 try블록이 입력되고 ctxnull이 될 수 없으므로 null 검사가 필요하지 않습니다.
kayahr

이 대답은 좋지 않습니다. try finally 블록에 실제 문제가 있습니다. 방금 테스트했지만 전혀 작동하지 않습니다.
HDJEMAI

12

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

((ClassPathXmlApplicationContext) fac).close();

6

Application 컨텍스트에는 ClassPathXmlApplicationContext의 인스턴스가 있고 동일한 인스턴스에는 close () 메서드가 있습니다. 간단히 appContext 개체를 CAST하고 아래와 같이 close () 메서드를 호출합니다.

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

리소스 누출 경고가 수정됩니다.


4

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

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

3

나는 똑같은 경고를 받았지만 내가 한 모든 것은 문제가 해결 된 ApplicationContext것과 같이 주요 기능 외부에서 선언 하는 것 private static뿐입니다.

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

8
이렇게하면 경고 문제는 해결되지만 컨텍스트를 열어두고 누출을 일으키는 실제 문제는 해결되지 않습니다. @SupressWarnings주석으로도 똑같이 할 수 있지만 근본 문제를 해결하는 것이 더 낫다고 생각하지 않습니까?
Xtreme Biker

네 말이 맞아요 .. 그 순간 저를위한 해결책 이었죠.
Elysium

이것은 좋은 대답이 아닙니다. 실제 문제는 동일하게 유지되기 때문에, 즉 리소스 누출이 있으므로 컨텍스트가 닫히지 않습니다.
HDJEMAI

2

전송은이 문제에 대한 올바른 해결 방법입니다. 아래 줄을 사용하여 동일한 문제에 직면했습니다. ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

경고를 해결하려면 ctx 아래와 같이 개체를 한 다음 닫으십시오. ((AnnotationConfigApplicationContext) ctx).close();


1

컨텍스트를 ConfigurableApplicationContext로 다운 캐스트합니다.

((ConfigurableApplicationContext)context).close();

((ConfigurableApplicationContext)(context)).close();이것이 정답이다 할 수있다
Bhargav 모디

amit28의 대답이 맞습니다. 답이 유용하지 않은 이유는 무엇입니까?
Rudy Vissers 2015-06-22

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

제 경우에는 누출이 사라집니다


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

0

ClassPathXmlApplicationContext 를 사용하는 경우 다음을 사용할 수 있습니다.

((ClassPathXmlApplicationContext) context).close();

리소스 누수 문제를 해결합니다.

AbstractApplicationContext 를 사용하는 경우 close 메소드로이를 캐스팅 할 수 있습니다.

((AbstractApplicationContext) context).close();

응용 프로그램에서 사용하는 컨텍스트 유형에 따라 다릅니다.


0
import org.springframework.context.ConfigurableApplicationContext;

((ConfigurableApplicationContext)ctx).close();

2
이 질문에 대한 답이라고 생각하는 이유를 자세히 설명해 주시겠습니까?
Jeen Broekstra

ClassPathXMLApplicationContext 수퍼 클래스는 close () 메소드를 포함하는 ConfigurableApplicationContext를 구현합니다. 컨텍스트를 ConfigurableApplicationContext로 타입 캐스트하여 close () 메서드를 호출하면 리소스가 해제됩니다. 간단히 다음과 같이 할 수도 있습니다. ((ClassPathXmlApplicationContext) ctx) .close ();
Suseendran P

0

컨텍스트를 정적 변수로 만듭니다. 즉, 컨텍스트가 더 이상 기본 메서드의 범위에 국한되지 않고 클래스의 모든 정적 메서드에서 사용할 수 있습니다. 따라서 도구는 더 이상 메소드의 끝에서 닫아야한다고 가정 할 수 없으므로 더 이상 경고를 발행하지 않습니다.

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

       }
}

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


0

이 링크에 제공된 라이브러리에 Core jar를 입력하는 간단한 솔루션이 있습니다. [spring 용 코어 jar 파일 다운로드] [1] [1] : https://static.javatpoint.com/src/sp/spcorejars. 지퍼


1
마크 다운 문서를 확인하고 미리보기를 사용하세요. URL이 잘린 것 같습니다.
Leo

-1

close 메소드가 ConfigurableApplicationContext 인터페이스에 추가되었으므로 액세스 할 수있는 최선의 방법은 다음과 같습니다.

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

// Use the context...

context.close();
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.