Как я могу определить, в каком контексте Java-апплета запущен, не передавая идентификатор?
Вопрос
Я являюсь частью команды, которая разрабатывает довольно большой Java-апплет Swing.Большая часть нашего кода является устаревшей, и в нем содержится множество ссылок на синглтоны.Мы объединили их все в один синглтон "Контекст приложения".Теперь нам нужно создать какой-то способ разделения общего контекста (общего для всех отображаемых в данный момент апплетов) и необщего контекста (специфичного для каждого отображаемого в данный момент апплета).
Однако у нас нет идентификатора в каждом из местоположений, которые вызывают синглтон, и мы не хотим распространять идентификатор на все местоположения.Какой самый простой способ определить, в каком контексте апплета мы запускаем?(Я пробовал возиться с загрузчиками классов, группами потоков, идентификаторами потоков...пока я не смог найти ничего, что позволило бы мне определить источник вызова).
Решение
Одиночки - это зло, чего ты ожидал?;)
Возможно, наиболее всеобъемлющим подходом было бы загрузить основную часть апплета в другой загрузчик классов (используйте java.net.URLClassLoader.newInstance).Затем используйте WeakHashMap, чтобы связать загрузчик классов с апплетом.Если бы вы могли разделить большую часть кода на общий загрузчик классов (как родительский для каждого загрузчика классов для каждого апплета) и на обычную кодовую базу апплета, это было бы быстрее, но и больше работы.
Другие хаки:
Если у вас есть доступ к какому-либо компоненту, вы можете повторно использовать Component.getParent или SwingUtilities.getRoot.
Если вы находитесь в потоке для каждого экземпляра апплета, то вы можете настроить ThreadLocal.
Из EDT вы можете прочитать текущее событие из очереди (java.awt.EventQueue.getCurrentEvent()) и, возможно, найти компонент из этого.В качестве альтернативы отправьте EventQueue с переопределенным методом dispatchEvent.
Другие советы
Если я вас правильно понял, идея состоит в том, чтобы получить другой "одноэлементный" объект для каждого вызывающего объекта или "контекста".Одна вещь, которую вы можете сделать, это создать локальную глобальную переменную потока, в которую вы записываете идентификатор текущего контекста.(Это можно сделать с помощью AOP.) Затем в одноэлементном получателе идентификатор контекста извлекается из локального потока для использования в качестве ключа к правильному экземпляру "singleton" для вызывающего контекста.
Что касается AOP, не должно возникнуть проблем с его использованием в апплетах, поскольку, в зависимости от ваших пожеланий, советы сплетаются во время компиляции, а JAR добавляется к зависимостям времени выполнения.Следовательно, во время выполнения не должно оставаться никаких особых доказательств AOP.
@Хьюго относительно threadlocal:
Я думал об этом решении.Однако в ходе экспериментов я обнаружил две проблемы, связанные с таким подходом:
- Общий поток (подключения к серверу и т.д.) Является проблематичным.Однако это можно решить, уделив особое внимание этим потокам (все они находятся под моим контролем и в значительной степени изолированы от устаревшего кода).
- Поток EDT является общим для всех апплетов.Мне не удалось найти способ принудительно создавать новый поток EDT для каждого апплета.Это означает, что threadlocal для EDT будет общим для всех апплетов.Эту проблему я понятия не имею, как решить.Предложения?