Могу ли я подключить крючок отключения Java через jvm
. Я имею в виду, могу ли я отключиться от моей JVM к серверу weblogic, работающему в другом jvm
?
Перехватчик отключения Java на разных JVM
Ответы (2)
Часть перехватчика завершения работы находится в Время выполнения.
Часть в JVM вам придется реализовывать самостоятельно, потому что только вы знаете, как ваши JVM могут обнаруживать и идентифицировать себя.
Это может быть так же просто, как создать прослушивающий сокет при запуске JVM1 и отправить ему номер порта JVM2. JVM1 отправит уведомление о завершении работы JVM2 (на этот порт) в своем перехватчике завершения работы.
Короткий ответ: вы можете, но не сразу, и есть некоторые подводные камни, поэтому, пожалуйста, прочитайте раздел подводных камней в конце.
Перехватчик завершения работы должен быть объектом потока 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, вы должны использовать динамический язык и передать этот скрипт удаленной службе, например. заводной.