Предисловие
«Динамический агент» фактически происходит из режима прокси в режиме проектирования, а прокси -режим использует объект прокси для выполнения запросов пользователей и блокирует доступ пользователей к реальным объектам.
Чтобы привести самый простой пример, мы хотим «FQ», чтобы получить доступ к иностранным веб -сайтам, потому что у нас нет всех иностранных IPS, вы можете отправить ваш запрос данных по запросу на тех иностранных хостов, которые не заблокированы, а затем отправляете запрос в пункт назначения, настройка иностранного хоста и перенаправить его обратно на наш внутренний хост после получения ответного сообщения.
В этом примере иностранный хост является прокси -объектом, и те хосты, которые отбрасываются на стену, являются реальными объектами. Мы не можем напрямую получить доступ к реальным объектам, но мы можем косвенно получить его через прокси.
Одним из преимуществ прокси -режима является то, что все внешние запросы проходят через прокси -объект, а объект прокси имеет право контролировать, разрешено ли вам по -настоящему получить доступ к реальному объекту. Если есть незаконное запрос, объект прокси может полностью отклонить вас без проблем с реальным объектом.
Одним из самых типичных применений прокси -режима является Spring Framework. Spring AOP использует ориентированное на аспект программирование для изоляции фактической бизнес-логики от связанных исключений журнала и другой информации. Каждый раз, когда вы запрашиваете бизнес -логику, она соответствует прокси -объекту. В дополнение к выполнению необходимых проверок разрешений и печати журнала, этот объект прокси является реальным блоком обработки бизнес -логики.
Статический прокси
Есть два основных реализации прокси -модели, «Статический прокси» и «Динамический прокси». Существенное различие между этими двумя заключается в том, что первый класс прокси требует ручного кодирования программистами, в то время как последний класс прокси -сервера автоматически генерируется. Итак, именно поэтому вы почти не слышали о концепции «статического прокси». Конечно, естественно, легче понять «динамический прокси».
Одна вещь, которую вы должны быть ясно, состоит в том, что прокси -объект прокси все методы реального объекта, то есть прокси -объект должен предоставить, по крайней мере, одно и то же имя метода, что и настоящий объект для вызова, поэтому объект прокси должен определить все методы, принадлежащие реальному объекту, включая методы в родительском классе.
Давайте посмотрим на простой статический прокси -пример:
Чтобы проиллюстрировать эту проблему, мы определяем интерфейс Iservice и позволяем нашему реальному классу наследовать и реализовать интерфейс, чтобы в нашем реальном классе было два метода.
Итак, как можно определить класс прокси для завершения прокси для реальных объектов?
Вообще говоря, суть класса прокси - определить все методы в реальном классе и добавить некоторые другие операции внутри метода и, наконец, вызвать метод реального класса.
Класс прокси должен для прокси -сервера всех методов в реальном классе, то есть методов, которые точно такие же, как и те методы в реальном классе, и метод реального класса будет косвенно называется внутри этих методов.
Так что, вообще говоря, класс прокси выберет непосредственно наследовать все интерфейсы и родительские классы реального класса, чтобы получить все родительские методы подписи реального класса, то есть для первого привязки всех родительских методов.
Затем прокси не является родительским методом в реальном классе. В примере здесь метод Doservice является собственным методом реального класса. Наш класс прокси также должен определить метод с той же подписью метода для его прокси.
Таким образом, даже если наш прокси -класс будет завершен, все методы в реальном классе могут быть оцениваются через класс прокси в будущем. Так:
public static void main (String [] args) {RealClass RealClass = new RealClass (); ProxyClass ProxyClass = новый ProxyClass (RealClass); proxyclass.sayhello (); proxyclass.doservice ();}ProxyClass, как объект класса Proxy, может прокси -сервер в реальном классе и распечатать некоторую «незначительную» информацию до выполнения этих методов.
Это в основном основная идея реализации прокси -модели, но разница между динамическим прокси и таким видом статического прокси заключается в том, что динамический прокси не требует определений наших методов один за другим, и виртуальная машина автоматически генерирует эти методы для вас.
Динамический прокси -механизм JDK
Что отличает динамический прокси от статического прокси, так это то, что прокси -класс динамического прокси -сервера динамически создается виртуальной машиной во время выполнения и очищается, когда виртуальная машина удаляется.
Мы повторно используем классы, используемые в приведенном выше статическом прокси, чтобы увидеть, как динамический прокси JDK может приблизить все методы экземпляра определенного класса.
Определите класс обработки обработки:
Dynamic Proxy API в основной функции вызывает JDK для генерации экземпляра класса прокси:
Есть все еще довольно много кода, давайте проанализируем его кусочком. Во -первых, RealClass реализует интерфейс Iservice в качестве нашего прокси -класса и определяет свой собственный метод Doservice внутри.
Затем мы определяем класс обработки, который наследует интерфейс vlocationhandler и реализует его уникально объявленный метод Anloke. Кроме того, мы должны объявить поле участника для хранения реальных объектов, то есть прокси -объектов, потому что любой метод, который мы прокси, в основном основан на соответствующих методах реальных объектов.
Что касается роли этого метода вызова и значимости различных формальных параметров, мы проведем подробный анализ, когда отражаем исходный код прокси.
Наконец, определите наш класс обработки и в основном выполняйте динамический прокси на основе JDK. Основным методом является метод NewProxyInstance класса прокси. Этот метод имеет три параметра. Одним из них является загрузчик класса, второй - это коллекция всех интерфейсов, реализованных классом Proxy, а третьим является нашим индивидуальным классом процессора.
Виртуальная машина использует загрузчик класса, который вы предоставляете во время выполнения, загружают все указанные классы интерфейса в область метода, а затем отражает и считывает методы в этих интерфейсах и объединяет класс процессора для генерации типа прокси.
Последнее предложение может быть немного абстрактным. Как «в сочетании с классами процессоров для генерации типа прокси»? В связи с этим мы указываем параметры запуска виртуальной машины и позволяем ему сохранить сгенерированный файл класса класса прокси.
-Sun.misc.proxygenerator.saveGeneratedFiles = true
Мы декомпилируем этот файл класса через сторонние инструменты, и есть много контента. Мы разделили анализ:
Прежде всего, название этого прокси -класса очень случайно. Если в программе есть несколько классов по доверенности, «$ Proxy + Number» - это имя их класса.
Далее вы заметите, что этот класс прокси наследивает класс прокси и интерфейс Iservice, который мы указали (ранее, если было указано несколько интерфейсов, здесь будут унаследованы несколько интерфейсов).
Затем вы обнаружите, что этот конструктор требует параметра типа vocationHandler, и тело конструктора - передать этот экземпляр InvocationHandler в соответствующее поле Porxy Partive Class Proxy для хранения. Это также одна из причин, по которой все классы прокси должны использовать прокси в качестве родительского класса, который должен публиковать поле vocationHandler в родительском классе. Позже мы узнаем, что этот небольшой дизайн приведет к роковому недостаткам динамического прокси на основе JDK, который будет введен позже.
Этот контент также является относительно важной частью прокси -класса. Он будет выполнен, когда виртуальная машина статически инициализирует класс прокси. Этот большой кусок кода завершает функцию отражения всех методов в интерфейсе, и все отраженные методы хранятся, соответствующие полю типа метода.
Кроме того, виртуальная машина также отражает три общих метода в объекте, то есть класс прокси также предоставит реальный объект, унаследованный от объекта.
В последней части мы видим, что виртуальная машина отражает все методы, которые должны быть доверенны на основе блока статической кода инициализации и генерирует для них методы прокси.
Эти методы выглядят как много кода, но на самом деле они представляют собой лишь одну строку кода, которая снимает класс процессора, хранящийся во время экземпляра от Proxy родительского класса, и вызывает его метод вызова.
Параметры метода в основном одинаковы. Первым параметром является текущий экземпляр класса прокси (он доказывает, что это бесполезно передавать этот параметр в прошлом), второй параметр - это экземпляр метода метода, а третий параметр - это формальный набор параметров метода. Если нет, то это ноль.
Теперь давайте посмотрим на индивидуальный класс процессора:
Все методы класса прокси -класса будут вызывать метод вызова класса процессора и пройти в текущем методе класса прокси. Этот метод вызова может выбрать, чтобы метод был вызван нормально, или пропустить вызов метода, и даже сделать несколько дополнительных вещей до и после того, как метод фактически вызван.
Это основная идея динамического прокси JDK. Давайте кратко суммируем весь процесс вызова.
Прежде всего, определение класса процессора имеет важное значение, и оно должно быть связано с реальным объектом, то есть экземпляром класса прокси.
Затем мы называем любой метод класса прокси из внешней части, и из декомпилированного исходного кода мы знаем, что метод класса прокси вместо этого вызовет метод вызова процессора и пройти в наборе формальных параметров метода и метода.
Наконец, можно ли назвать метод нормально, зависит от того, действительно ли образец метод вызывает метод метода.
Фактически, динамический прокси, реализованный на основе JDK, ошибочен, и эти дефекты нелегко исправить, поэтому CGLIB популярен.
Некоторые дефекты и недостатки
Одиночный прокси -механизм
Я не знаю, заметили ли вы, что приведенные выше примеры недоступны. Класс прокси, созданный виртуальной машиной, наследует класс прокси, чтобы публично хранить свои собственные экземпляры класса процессора. Что это значит?
Единственное наследство Java говорит вам, что класс прокси больше не может наследовать какой -либо другой класс, поэтому методы в родительском классе класса прокси, естественно, не смогут получить, то есть класс прокси не может прокси -дипломировать любые методы родительского класса в реальном классе.
Кроме того, это еще одна небольшая деталь. Интересно, заметили ли вы это. Я написал это так.
Метод Sayhello здесь - это реализованный интерфейс Iservice, в то время как метод Doservice - это метод, который принадлежит собственной реальности. Но мы не видим этот метод из класса прокси, что означает, что этот метод не является доверенным.
Следовательно, динамический прокси -механизм JDK является одиноким, и он может только прокси -методы в сборе интерфейса класса прокси.
Недружелюбное возвратное значение
Обратите внимание, что NewProxyInstance возвращает экземпляр класса прокси «$ proxy0», но он возвращается в виде типа объекта, и вы не можете заставить экземпляр объекта к типу "$ proxy0".
Хотя мы знаем, что этот экземпляр объекта на самом деле является типом «$ proxy0», тип «$ proxy0» не существует в течение периода компиляции, и компилятор, естественно, не позволит вам заставить его не существует. Следовательно, это, как правило, заставит его быть одним из интерфейсов, реализованных этим классом прокси.
RealClass rc = new RealClass (); Myhanlder hanlder = new Myhanlder (rc); iService obj = (iService) proxy.newproxyInstance (rc.getClass (). getClassloader (), новый класс [] {iservice.class}, hanlder);Программа запуска вывода:
Прокси начало ...... Привет, мир ... окончание прокси ......
Затем возникает вопрос снова. Если наш класс прокси реализует несколько интерфейсов, к какому типу интерфейса вы должны его заставлять? Теперь, предполагая, что класс прокси реализует интерфейсы A и B, то, если последний экземпляр вынужден A, вы, естественно, не можете вызвать все методы в интерфейсе B, реализованные классом Proxy, и наоборот.
Это напрямую приводит к результату. Вы должны знать, какой метод, в каком интерфейсе. Если вы приведете его к соответствующему интерфейсу перед вызовом метода, это довольно недружелюбно.
Вышесказанное - это то, что мы считаем элегантным в динамическом прокси -механизме, основанном на JDK. Конечно, его преимущества определенно больше, чем эти недостатки. В следующей статье мы представим динамическую прокси -библиотеку CGLIB, широко используемая различными рамками. Его базовый слой основан на рамках операции ByteCode ASM и больше не опирается на наследство для его реализации, что идеально решает недостатки единого прокси JDK.
Все коды, изображения и файлы в статье хранятся в облаке на моем GitHub:
(https://github.com/singleyam/overview_java)
Вы также можете загрузить локально.
Суммировать
Вышеуказанное - все содержание этой статьи. Я надеюсь, что содержание этой статьи имеет определенную справочную ценность для каждого обучения или работы. Если у вас есть какие -либо вопросы, вы можете оставить сообщение для общения. Спасибо за поддержку Wulin.com.