Spring ApplicationContext - утечка ресурсов: контекст никогда не закрывается

В приложении spring MVC я инициализирую переменную в одном из классов службы, используя следующий подход:

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

UserLibrary - это сторонняя утилита, которую я использую в своем приложении. Вышеупомянутый код генерирует предупреждение для переменной "context". Предупреждение показано ниже:

Resource leak: 'context' is never closed

Я не понимаю предупреждения. Поскольку приложение является приложением spring MVC, я не могу действительно закрыть/уничтожить контекст, поскольку я обращаюсь к службе во время работы приложения. Что именно предупреждение пытается рассказать мне?

Ответ 1

Поскольку контекст приложения представляет собой ResourceLoader (т.е. операции ввода-вывода), он потребляет ресурсы, которые необходимо освободить в какой-то момент. Это также расширение AbstractApplicationContext, которое реализует Closable. Таким образом, он получил метод close() и может быть использован в операторе try-with-resources.

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

Если вам действительно нужно создать этот контекст, это другой вопрос (вы связались с ним), я не буду комментировать это.

Верно, что контекст закрывается неявно, когда приложение остановлено, но это недостаточно. Eclipse прав, вам нужно принять меры, чтобы закрыть его вручную для других случаев, чтобы избежать утечек загрузчика.

Ответ 2

close() не определен в интерфейсе ApplicationContext.

Единственный способ безопасно избавиться от предупреждения:

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

Или, в Java 7

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

Основное отличие состоит в том, что, поскольку вы создаете экземпляр контекста явно (т.е. с помощью new), вы знаете класс, который вы создаете, поэтому вы можете соответствующим образом определить свою переменную.

Если вы не создавали экземпляр AppContext (т.е. используя тот, который предоставлен Spring), вы не можете его закрыть.

Ответ 3

Простой литье решает проблему:

((ClassPathXmlApplicationContext) fac).close();

Ответ 4

Даже у меня было то же предупреждение, все, что я сделал, было объявлено 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();
    }
}

Ответ 5

В контексте приложения есть экземпляр класса ClassPaспасибоmlApplicationContext, а тот же метод close(). Я бы просто CAST-объект appContext и вызывать метод close(), как показано ниже.

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

Это устранит предупреждение о утечке ресурсов.

Ответ 6

попробуйте это. вам нужно применить заливку, чтобы закрыть applicationcontext.

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

Ответ 7

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

В моем случае утечка исчезает

Ответ 8

Перетащите контекст в ConfigurableApplicationContext.

((ConfigurableApplicationContext)context).close();

Ответ 9

Если вы используете ClassPaспасибоmlApplicationContext, вы можете использовать

((ClassPathXmlApplicationContext) context).close();

чтобы закрыть проблему утечки ресурсов.

Если вы используете AbstractApplicationContext, вы можете использовать это методом close.

((AbstractApplicationContext) context).close();

Это зависит от типа контекста, используемого в приложении.

Ответ 10

import org.springframework.context.ConfigurableApplicationContext;

((ConfigurableApplicationContext)ctx).close();

Ответ 11

Вы ставите контекст статической переменной, а это означает, что контекст доступен для всех статических методов в классе и не ограничивается областью основного метода. Поэтому инструмент не может предположить, что он должен быть закрыт в конце метода больше, поэтому он больше не выдаёт предупреждение.

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

       }
}

Ответ 12

Закрытие метода было добавлено в интерфейс ConfigurableApplicationContext, поэтому лучше всего вы можете получить доступ к нему:

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

// Use the context...

context.close();