Перехватчик отключения Java на разных JVM

Могу ли я подключить крючок отключения Java через jvm . Я имею в виду, могу ли я отключиться от моей JVM к серверу weblogic, работающему в другом jvm?


person chiru    schedule 16.01.2014    source источник
comment
Нет, ты не можешь. Ничего в Javadoc не предполагает иного.   -  person user207421    schedule 16.01.2014


Ответы (2)


Часть перехватчика завершения работы находится в Время выполнения.

Часть в JVM вам придется реализовывать самостоятельно, потому что только вы знаете, как ваши JVM могут обнаруживать и идентифицировать себя.

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

person Oleg Mikheev    schedule 16.01.2014
comment
Спасибо за ваш вклад, какие-нибудь примеры, не могли бы вы мне помочь? - person chiru; 16.01.2014

Короткий ответ: вы можете, но не сразу, и есть некоторые подводные камни, поэтому, пожалуйста, прочитайте раздел подводных камней в конце.

Перехватчик завершения работы должен быть объектом потока Runtime.addShutdownHook(Thread), к которому может получить доступ jvm. Таким образом, он должен быть создан внутри этого jvm.

Единственный способ, который я вижу, - это реализовать Runnable, который также является Serializable, и какую-то удаленную службу (например, RMI), которую вы можете передать SerializableRunnable. Затем эта служба должна создать Thread, передать SerializableRunnable конструктору этого Thread и добавить его в качестве обработчика завершения работы в Runtime.

Но есть и другая проблема в этом случае. SerializableRunnable не имеет ссылок на объекты в jvm удаленной службы, и вам нужно найти способ, как этот SerializableRunnable может их получить или внедрить. Таким образом, у вас есть выбор между ServiceLocator или механизм внедрения зависимостей. В следующих примерах я буду использовать шаблон локатора сервисов.

Я бы предложил определить интерфейс следующим образом:

 public interface RemoteRunnable extends Runnable, Serializable {

       /**
         * Called after de-serialization from a remote invocation to give the
         * RemoteRunnable a chance to obtain service references of the jvm it has
         * been de-serialized in.
         */
      public void initialize(ServiceLocator sl);
 }

Метод удаленного обслуживания может выглядеть следующим образом

 public class RemoteShutdownHookService {

    public void addShutdownhook(RemoteRunnable rr){
        // Since an instance of a RemoteShutdownHookService is an object of the remote
        // jvm, it can provide a mechanism that gives access to objects in that jvm.

        // Either through a service locator
        ServiceLocator sl = ...;
        rr.initialize(sl);

        // or a dependency injection. 
        // In case of a dependecy injection the initialize method of RemoteRunnable
        // can be omitted.
        // A short spring example:
        //
        // AutowireCapableBeanFactory beanFactory = .....;
        // beanFactory.autowireBean(rr);

        Runtime.getRuntime().addShutdownHook(new Thread(rr));
    }

 }

и ваш RemoteRunnable может выглядеть примерно так

public class SomeRemoteRunnable implements RemoteRunnable {

    private static final long serialVersionUID = 1L;
    private SomeServiceInterface someService;

    @Override
    public void run() {
        // call someService on shutdown
        someService.doSomething();
    }

    @Override
    public void initialize(ServiceLocator sl) {
        someService = sl.getService(SomeServiceInterface.class);
    }

 }

Подводные камни

Есть только одна проблема с этим подходом, которая не очевидна. Класс реализации RemoteRunnable должен быть доступен в пути к классам удаленной службы. Таким образом, вы не можете просто создать новый класс RemoteRunnable и передать его экземпляр удаленной службе. Вам всегда нужно добавлять его в путь к классам удаленных JVM.

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

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

person René Link    schedule 16.01.2014
comment
отличный дизайн, но некоторые люди рекомендуют избегать сериализации любой ценой - person Oleg Mikheev; 16.01.2014
comment
@OlegMikheev Знаете, почему они это рекомендуют? - person René Link; 16.01.2014
comment
с сериализацией вы ограничиваете себя одной и той же версией JVM для всех сторон, и есть так много вещей, которые нужно помнить о сериализации, что лучше всего не использовать ее (цитируя Боба Ли) - person Oleg Mikheev; 16.01.2014
comment
Сериализация @OlegMikheev не ограничивает вас одной и той же версией jvm для всех сторон. В противном случае исключения для разных JVM не будут работать (они сериализуемы). Конечно, класс, который вы проходите через разные JVM, должен быть бинарно совместим с классами в этой JVM. Вот почему вы должны позаботиться о версии класса, развернутой на разных JVM. - person René Link; 16.01.2014
comment
Это верно в теории, но в реальной жизни случаются такие проблемы периодически. Во времена Java 1.3 проблемы с сериализацией были катастрофой, в последнее время эти проблемы встречаются реже, может быть потому, что никто не использует ее? :) - person Oleg Mikheev; 16.01.2014
comment
@OlegMikheev Я согласен с тем, что java.io.InvalidClassException возникает часто, но я думаю, что это происходит из-за таких страниц, как wiki .eclipse.org/Evolving_Java-based_API_2 не очень внимательно читается. :) - person René Link; 16.01.2014