Чисто уничтожить контекст приложения Spring

Я столкнулся с проблемами, убедившись, что контекст приложения Spring, который я уничтожаю, полностью исчез, и не могу видеть объект, собираемый мусором. Когда я смотрю на экземпляр в VisualVM, я вижу, что существует ряд незавершенных ссылок как на контекст, так и на его фабрику компонентов, которые остаются после закрытия и уничтожения контекста. Все это должно быть связано с первоначальной настройкой фабрики компонентов (во время метода обновления AbstractApplicationContext), которая регистрирует фабрику компонентов и контекст с различными постпроцессорами компонентов и т. д.

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

Я спрашиваю, поскольку программное обеспечение, над которым я работаю в данный момент, может динамически создавать/уничтожать, а затем воссоздавать контекст (поскольку модули динамически загружаются и выгружаются), а оставшиеся элементы контекста и bean factory вызывают проблемы с такими компонентами, как как spring-data-jpa (особенно прокси, который связывает интерфейсы репозитория с реализациями репозитория).

Кто-нибудь знает способ, с помощью которого я могу чисто и полностью удалить контекст и фабрику компонентов без необходимости полностью закрывать виртуальную машину, которая изначально ее создала?


person Mike    schedule 02.11.2016    source источник


Ответы (3)


Изучив это снова недавно, я заметил, что я переопределял метод doClose() контекста, чтобы убедиться, что компоненты были полностью уничтожены, но не вызывал метод super.doClose(), что означало, что LiveBeansView.unregisterApplicationContext() / destroyBeans() / getLifecycleProcessor().onClose() и closeBeanFactory() не вызывались.

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

person Mike    schedule 04.01.2017

Если вы используете контейнер Spring IoC в среде, отличной от веб-приложений; например, в богатой клиентской среде рабочего стола; вы регистрируете перехватчик выключения с помощью JVM. Это обеспечивает плавное завершение работы и вызывает соответствующие методы уничтожения ваших одноэлементных компонентов, чтобы высвободить все ресурсы. Конечно, вы все равно должны правильно настроить и реализовать эти обратные вызовы уничтожения.

Чтобы зарегистрировать ловушку отключения, вы должны вызвать метод registerShutdownHook(), объявленный в классе AbstractApplicationContext:

Код

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public final class startup {

  public static void main(final String[] args) throws Exception {
      AbstractApplicationContext ctx
          = new ClassPathXmlApplicationContext(new String []{"beans.xml"});

      // add a shutdown hook for the above context... 
      ctx.registerShutdownHook();

      // app runs here...

      // main method exits, hook is called prior to the app shutting down...
  }
}
person Sagar Tambade    schedule 23.12.2016
comment
Спасибо, но, как я уже упоминал, это не имеет ничего общего с отключением всего контейнера. Это создание/уничтожение контекста приложения без закрытия контейнера, поэтому перехватчик выключения не поможет. - person Mike; 28.12.2016

Вызовите destroy в контексте и установите null для всех переменных, ссылающихся на экземпляр контекста вашего приложения:

AbstractApplicationContext context = new ClassPathXmlApplicationContext(new String []{"beans.xml"});

// ... do your stuff

context.destroy();
context = null;
person walkeros    schedule 27.12.2016
comment
Спасибо, но я изучил уничтожение, и оно существует только как очень особый случай (где контекст - это компонент внутри другой фабрики компонентов), и в любом случае реализация по умолчанию просто вызывает close(); Я определенно закрываю контекст и удаляю любые ссылки на контекст, но дело в том, что фабрика компонентов внутри контекста приложения регистрирует себя (или регистрируется) рядом других внутренних экземпляров в Spring, и поэтому общая ссылка никогда не выпущено (установка значения null везде в нашем коде не имеет никакого эффекта. - person Mike; 28.12.2016