2016-08-27 2 views
1

Reference: dynamic load java codeможет динамически загружать классы, чтобы переподчинить статические ссылки?

public interface Postman { 
    void deliverMessage(String msg); 
} 

//loaded by dynamic class loader, with parent class loader pointing to main 
public class PostmanImpl implements Postman { 
} 

public class PostmanApp { 
    public static void main(String[] args) throws Exception { 
     Postman postman = getPostman(); 
     while (true) { 
      //postman.deliverMessage(msg); 
      getPostman().deliverMessage(msg); 
     } 
    } 
    private static Postman getPostman() { 
     // Omit for now, will come back later 
     // ??? 
    } 
} 

Как получить доступ к уточненному динамическому классу со статической ссылкой? По-видимому, прямая (нормальная) ссылка на объект динамического класса не будет делать трюк.

Я не совсем следую приведенному выше заявлению. а не apparent мне. Динамический загрузчик классов всегда будет ссылаться на загрузчик классов main как на загрузчик родительского класса, поэтому всегда работает интерфейс Postman, загрузчик динамического класса всегда загружает новый класс Impl, который совместим с interface.

InvocationHandler handler = new DynaCodeInvocationHandler(...); 
    Postman proxy = (Postman) Proxy.newProxyInstance(
       Postman.class.getClassLoader(), 
       new Class[] { Postman.class }, 
       handler); 

В конечном итоге автор предложил использовать прокси для делегирования вызовов по интерфейсу для недавно загруженной реализации.

По-видимому, прямая (нормальная) ссылка на объект динамического класса не будет делать трюк.

В чем проблема с прямым назначением ссылки на новый класс? почему в итоге нужен Proxy?

+0

* «В чем здесь проблема?» * Что это за проблема? Это не ясно из вашего вопроса. * «Почему в конце концов нужен« прокси »?» * Это не так. –

ответ

1

Вы уже исправили код, чтобы он не был необходим.

Исходный код делает это (упрощенный):

Postman p = getPostman(); 
while(true) { 
    p.deliverMessage(); 
} 

Там нет никакого способа для кода в Postman изменить объект p относится. Когда он загружает обновленный класс и создает новый экземпляр нового класса, p по-прежнему относится к старому экземпляру старого класса.

Но если вы сделаете это вместо:

while(true) { 
    getPostman().deliverMessage(); 
} 

getPostman затем возвращает экземпляр нового класса, как только он будет загружен, и нет никаких проблем.

+0

странно, так что это просто вопрос переключения между старой ссылкой и новой ссылкой и отслеживания этого. в чем смысл сложной сложности. может быть, это более удобно и эффективно? @dasblinkenlight, согласны ли вы с этим? – zinking

+1

@zinking. По-прежнему существует проблема, потому что вы не можете передать 'getPostman' методу или конструктору, который принимает' Postman', только результат вызова 'getPostman()'. Если метод или конструктор решает сохранить 'Postman', вы вернетесь к той же проблеме устаревших ссылок. Поэтому все пользователи по дороге должны придерживаться одного и того же 'getPostman(). DoSomething()' pattern. Это добавляет гораздо больше проблем, чем решает. – dasblinkenlight

2

Java не позволяет изменять тип экземпляра во время выполнения. Динамически загруженный класс всегда является новым классом, несовместимым со старым, даже если он является структурно эквивалентным или даже одним и тем же байт-кодом (они могут иметь общий суперкласс или интерфейс).

Итак, если вы раздаете простые экземпляры клиентам, нет способа их «напомнить». Вы можете только заблокировать экземпляры и заставить клиента получить новый экземпляр.

Прокси позволяет вам изменять делегат, на который вы перенаправляете вызовы. Таким образом, вы раздаете прокси-сервер своему клиенту. Когда вы загружаете новую версию класса, вы можете изменить свойство прокси. Все клиенты могут продолжить работу над своей ссылкой на прокси.

1

Главное, что делает динамику класса нашей способностью перенаправлять ссылку на динамический класс по своему усмотрению.

Мы не можем сделать это без прокси-сервера:

No proxy

ссылка показано красного цвета представляет собой ссылку из переменной Java к объекту. Мы не владеем переменной, и мы не знаем, как она используется. Клиент может передавать переменную как параметр или назначать ее полю, создавая несколько копий красной ссылки, что делает невозможным ее управление.

Proxy добавляет еще один уровень косвенности:

With a proxy

Мы до сих пор не владеют красной ссылке. Тем не менее, зеленая ссылка находится внутри прокси-сервера, поэтому она полностью находится под нашим контролем. Если мы решим перенаправить его на другой объект, и у нас есть несколько клиентов, ссылающихся на него, все клиентские объекты будут перенаправлены после одного переназначения.

+0

Можете ли вы немного рассказать о том, что ссылочное задание точно так же, как «указатель». процесс загрузки/ссылки не вызывает проблем, какая часть JVM предотвращает это? – zinking

+0

@zinking Изменение ссылки действительно похоже на присвоение указателя. Проблема в том, что мы не знаем, где ссылки. Например, когда клиент делает «Postman p = getPostman()», и мы возвращаем что-то, у нас нет способа переназначить 'p'. Кроме того, клиент может делать «Postman anotherP = p', который полностью выходит за пределы нашего кода. Мы даже не знаем, что 'copyP' существует! Если мы вернем прокси, с другой стороны, все, что нам нужно сделать, это сохранить ссылку на наш прокси-сервер: теперь ссылка на динамический класс является нашей, чтобы переназначить по своему усмотрению. – dasblinkenlight

Смежные вопросы