Minotaurus
|
addict
|
|
|
|
Рег.: 19.04.2007
|
Сообщений: 433
|
|
Рейтинг: 635
|
|
Вопрос по JavaSE classloading
25.11.2008 17:05
|
|
|
У меня есть закрытый проприетарный клиент для некоторого application сервера, который хранит настройки подключения в static полях некоторого класса. Из-за этого параллельная работа с разными серверами в несколько потоков становится невозможной. Я пытаюсь решить проблему, загружая копии всех классов отдельно для каждого сервера. Общая схема примерно такая
code:
package classloading;
public class Singleton {
public static String name;
}
code:
package classloading;
public class SingletonUser{
public String getSingletonName(){
return Singleton.name;
}
public void setSingletonName(String name){
Singleton.name = name;
}
}
code:
package classloading;
import java.net.URL;
import java.net.URLClassLoader;
public class Test {
public static void main(String[] args) throws Exception {
URL[] urlsToLoadFrom = new URL[] { new URL("file:subdir/") };
URLClassLoader loader1 = new URLClassLoader(urlsToLoadFrom);
URLClassLoader loader2 = new URLClassLoader(urlsToLoadFrom);
Class cls1 = Class.forName("classloading.SingletonUser", true, loader1);
Class cls2 = Class.forName("classloading.SingletonUser", true, loader2);
Object su1 = cls1.newInstance();
Object su2 = cls2.newInstance();
su1.getClass().getMethod("setSingletonName",new Class[]{String.class} ).
invoke(su,"111111");
su2.getClass().getMethod("setSingletonName",new Class[]{String.class} ).
invoke(su2,"222222");
}
}
В результате мы имеем 2 разные копии Singleton, и, соответственно, Singleton.name Проблема в том, что приходится работать через reflection, и вызовы методов становятся громоздкими. Как нибудь можно это исправить?
|
|
Yorik
|
|
|
|
|
Рег.: 01.09.2005
|
Сообщений: 2476
|
Из: Москва
|
Рейтинг: 633
|
|
|
[хренасе заморочка /] можно генерить при загрузке проксю (например, на Groovy) к классу настроек 
|
|
Mike
|
Ызарг
|
|
|
|
Рег.: 02.11.2002
|
Сообщений: 8098
|
|
Рейтинг: 2147
|
|
|
Quote:
Проблема в том, что приходится работать через reflection, и вызовы методов становятся громоздкими. Как нибудь можно это исправить?
Не понял только одного, почему ты Object потом не приводишь к Singleton? В твоем примере это будет работать.
|
|
Minotaurus
|
addict
|
|
|
|
Рег.: 19.04.2007
|
Сообщений: 433
|
|
Рейтинг: 635
|
|
Re: Вопрос по JavaSE classloading
[re: Mike]
25.11.2008 20:48
|
|
|
Quote:
Не понял только одного, почему ты Object потом не приводишь к Singleton? В твоем примере это будет работать.
Я пробовал, не прокатывает. Singleton.name начинают перекрываться. Но я на всякий случай завтра еще раз проверю.
Quote:
хренасе заморочка
Вроде по другому никак не сделать.
Quote:
можно генерить при загрузке проксю (например, на Groovy) к классу настроек 
Тогда же ведь придется декомпилировать и править код клиентской библиотеки? Я не буду этого делать, потому что имеющееся решение с рефлекшеном лучше. Представь, что Singleton и SingletonUser (это как раз и есть аналог моей закрытой библиотеки) ты не можешь менять, а можешь менять только Test. И в Test тебе надо создать несколько потоков и SingletonUser в каждом и вызывать в них методы SingletonUser, чтобы они не мешали друг другу(а мешают они потому что все обращаются к static полю класса Singleton)
|
|
botWi
|
|
|
|
|
Рег.: 22.11.2003
|
Сообщений: 10160
|
Из: Moscow
|
Рейтинг: 1764
|
|
|
В ответ на:
Я пробовал, не прокатывает. Singleton.name начинают перекрываться. Но я на всякий случай завтра еще раз проверю.
типа кастинг приводит к конкретизации класслоадера 
|
Хватит дрочить на рейтинги |
|
Mike
|
Ызарг
|
|
|
|
Рег.: 02.11.2002
|
Сообщений: 8098
|
|
Рейтинг: 2147
|
|
|
Quote:
Я пробовал, не прокатывает. Singleton.name начинают перекрываться. Но я на всякий случай завтра еще раз проверю.
Понятно. Сначала я не заметил static. Обычно singleton содержит только одно статическое поле (себя) и имеет private конструктор. Как раз для рефакторинга под нужды, подобные твоим.
Я собрал твой пример, и вызвал getSingletonName() через reflection. У меня получилось, что строка общая для обоих классов.
|
|
adiss
|
новичог
|
|
|
|
Рег.: 20.04.2004
|
Сообщений: 13
|
Из: Пушкино
|
Рейтинг: 48
|
|
Re: Вопрос по JavaSE classloading
[re: Mike]
25.11.2008 23:06
|
|
|
видимо, URL неверный указал и классы дефолтным (parent) класс-лоадером загрузились добавь assert cls1 != cls2
|
Не ходи туда, куда ведет дорога, иди туда, где нет пути, и оставь свой след. (Р.У.Эмерсон) |
|
Mike
|
Ызарг
|
|
|
|
Рег.: 02.11.2002
|
Сообщений: 8098
|
|
Рейтинг: 2147
|
|
Re: Вопрос по JavaSE classloading
[re: adiss]
25.11.2008 23:28
|
|
|
Quote:
видимо, URL неверный указал и классы дефолтным (parent) класс-лоадером загрузились
Так и есть. Я без понятия, что там надо ей указать, чтобы она загрузила разные. 
|
|
maxkar
|
enthusiast
|
|
|
|
Рег.: 19.10.2003
|
Сообщений: 291
|
|
Рейтинг: 15
|
|
|
В ответ на:
Проблема в том, что приходится работать через reflection, и вызовы методов становятся громоздкими. Как нибудь можно это исправить?
Подобная проблема часто решается при поддержке различных плагинов, которые загружаются внутри с использованием своих ClassLoader's. И решение там - базовый интерфейс, реализуемый соответствующими плагинами (сущностями). После создания объекта, его тип приводится к интерфейсу плагина и вся дальнейшая работа выполняется уже с этим интерфейсом.
code:
package classloading;
public interface SingletonInterface {
public String getSingletonName();
public void setSingletonName(String name);
}
code:
public class SingletonUser implements SingletonInterface {
// implementation skipped
}
code:
package classloading;
import java.net.URL;
import java.net.URLClassLoader;
public class Test {
public static void main(String[] args) throws Exception {
URL[] urlsToLoadFrom = new URL[] { new URL("file:subdir/") };
URLClassLoader loader1 = new URLClassLoader(urlsToLoadFrom);
URLClassLoader loader2 = new URLClassLoader(urlsToLoadFrom);
Class cls1 = Class.forName("classloading.SingletonUser", true, loader1);
Class cls2 = Class.forName("classloading.SingletonUser", true, loader2);
SingletonInterface su1 = (SingletonInterface) cls1.newInstance();
SingletonInterface su2 = (SingletonInterface) cls2.newInstance();
su1.setSingletonName("111111");
su2.setSingletonName("222222");
System.out.println(su1.getSingletonName());
System.out.println(su2.getSingletonName());
}
}
В данном случае SingletonInterface должен грузиться тем же classloader'ом, что и Test (например, быть в classpath). SingletonUser и Singleton - наоборот, должны грузиться отдельными classloader'ами (точно так же, как в исходном примере).
code:
maxkar@*** ~/jtest/loading $ ls classloading/*.class
classloading/SingletonInterface.class classloading/Test.class
maxkar@*** ~/jtest/loading $ ls subdir/classloading/*.class
subdir/classloading/Singleton.class subdir/classloading/SingletonUser.class
|
|