Ключом к реализации динамического прокси в Java являются эти две вещи: Proxy и InvocationHandler. Давайте начнем с метода Invoke в интерфейсе InvocationHandler и кратко объясним, как Java реализует динамический прокси.
Во -первых, полная форма метода Invoke заключается в следующем:
Public Object Invoke (Прокси -сервер объекта, метод метода, объект [] args) бросает Throwable {method.invoke (obj, args); return null;}Во -первых, давайте догадаемся, что метод - это метод, который называется, то есть метод, который необходимо выполнить; ARGS является параметром метода; Прокси, что это за параметр? Вышеупомянутая реализация метода Invoke () является относительно стандартной формой. Мы видим, что здесь не используются параметры прокси. Проверьте описание прокси в документации JDK, следующим образом:
Вызов метода на экземпляре прокси через один из его прокси -интерфейсов будет отправлен на метод вызовов экземпляра, передавая экземпляр прокси, java.lang.reflect.method объект, идентифицирующий метод, который был вызван, и массив объекта типа, содержащего аргументы.
Из этого мы можем знать, что приведенное выше предположение верно, и мы также знаем, что параметр прокси является экземпляром класса прокси.
Для удобства объяснения, вот простой пример для реализации динамического прокси.
// абстрактная роль (динамический прокси может только прокси -интерфейс) субъект общедоступного интерфейса {public void запрос (); } // Реальная роль: реализованный метод запроса () субъекта открытого класса RealSubject реализует субъект {public void request () {System.out.println («Из реального субъекта.»); }} // Реализовать vlocationhandler public class dynamicsubject реализует upocationhandler {частный объект obj; // Это преимущество динамического прокси. Инкапсулированный объект имеет тип объекта и принимает объекты любого типа Public DynamicSUBCEJECT () {} Public DynamicSUBJECT (Object obj) {this.obj = obj; } // Этот метод не является тем, что мы показываем, чтобы вызвать открытый объект viloke (объект прокси, метод метода, объект [] args) бросает throwable {System.out.println («Перед вызовом» + метод); method.invoke (obj, args); System.out.println ("после вызова" + метод); вернуть ноль; }} // Клиент: сгенерировать экземпляр прокси и вызовите метод запроса () public class client {public static void main (string [] args) бросает Throwable {// todo Автопогнированный метод загрязните Класс <?> Cls = rs.getClass (); // Ниже приводится одноразовое поколение субъекта по доверенности = (субъект) proxy.newproxyinstance (cls.getclassloader (), cls.getinterfaces (), ds); // Здесь вы можете доказать, что субъект является экземпляром прокси, выполнив результаты. Этот экземпляр реализует систему интерфейса субъекта. // Здесь вы можете видеть, что класс класса субъекта - это $ proxy0. Этот класс $ proxy0 наследует прокси и реализует систему интерфейса субъекта. System.out.print («Свойства в субъекте:»); Field [] field = subject.getClass (). GetDeclaredFields (); Для (Поле F: Field) {System.out.print (f.getName ()+","); } Методы в system.out.print ("/n"+"субъект:"); Method [] method = subject.getClass (). GetDeclaredMethods (); for (Method m: method) {System.out.print (m.getName ()+","); } Родительский класс System.out.println ("/n"+"Субъект:"+subject.getClass (). GetSuperClass ()); System.out.print ("/n"+"Субъект реализует интерфейс:"); Class <?> [] Интерфейсы = субъект.getClass (). GetInterfaces (); for (class <?> i: интерфейсы) {System.out.print (i.getName ()+","); } System.out.println ("/n/n"+"RUNE ROST:"); субъект.request (); }} Результат работы следующим образом: имя пакета здесь опущено, *** вместо этого
истинный
Класс класса предмета: класс $ proxy0
Свойства в предмете: M1, M3, M0, M2,
Методы в субъекте: запрос, хэшкод, равные, Тостронг,
Родительский класс предмета: класс java.lang.reflect.proxy
Интерфейс, реализованный субъектом: cn.edu.ustc.dynamicproxy.subject,
Результатом работы:
Прежде чем называть публичный абстрактный void ***. subject.request ()
От реального предмета.
После названия Public Abstract void ***. Subject.Request ()
PS: Информация об этом результате очень важна, по крайней мере для меня. Поскольку основная причина моего головокружения в динамическом прокси заключается в том, что я неправильно понял вышеупомянутый субъект. Request (), по крайней мере, я был смущен поверхностью и не нашел связь между субъектом и прокси. Однажды я был озадачен тем, как был подключен последний запрос на вызов () к indoke (), и как вызок знал, что запрос существует. Фактически, True и Class $ Proxy0 выше может решить много вопросов и в сочетании с исходным кодом $ proxy0, который будет упомянут ниже, он может полностью решить сомнения в динамическом прокси.
Из приведенного выше кода и результатов мы видим, что мы не называли метод infoke (), как показано, но этот метод действительно выполнил. Давайте проанализируем весь процесс ниже:
Судя по кодексу в клиенте, вы можете использовать метод NewProxyInstance в качестве прорыва. Давайте сначала посмотрим на исходный код метода NewProxyInstance в классе прокси:
Public Static Object NewProxyInstance (ClassLoader Loader, класс <?> [] Интерфейсы, vococationHandler h) бросает allosalargumentException {if (h == null) {бросить новый NullPointerException (); } / * * Посмотрите или генерируйте разработанную прокси -класс. */ Class cl = getProxyClass (погрузчик, интерфейсы); / * * Вызывает его конструктор с помощью спроектированного обработчика. * / try { / * * Прокси -исходный код имеет следующее определение: * Частный окончательный статический класс [] constructorparams = {vocationHandler.class}; * Минусы - это метод конструктора с формальными параметрами типа vlocationHandler*/ constructor = cl.getConstructor (ConstructOrparams); return (object) ons.newinstance (new Object [] {h}); } catch (nosuchmethodexception e) {бросить новый InternalError (e.toString ()); } catch (allogalaccessexception e) {бросить новый InternalError (e.toString ()); } catch (instantiationException e) {бросить новый InternalError (e.toString ()); } catch (vococationTargetException e) {бросить новый InternalError (e.toString ()); }} Proxy.newProxyInstance (ClassLoader Loader, класс <?> [] Интерфейсы, vocationHandler h) делает следующие вещи.
(1) Вызовите метод getProxyClass (загрузчик, интерфейсы) на основе загрузчика и интерфейсов параметров, создать класс Proxy $ proxy0. $ Proxy0, реализует интерфейсы интерфейсов и наследует класс Proxy.
(2) создать экземпляру $ proxy0 и pass dynamicsubject в конструкторе, затем $ proxy0 вызывает конструктор прокси -прокси -класса родительского класса и присваивает значение H, следующим образом:
Class Proxy {vocationHandler h = null; Защищенный прокси (vococationhandler h) {this.h = h; } ...}Давайте посмотрим на исходный код, который наследует Proxy $ Proxy0:
Public Final Class $ proxy0 расширяет прокси -прокси реализует субъект {частный статический метод M1; частный статический метод M0; частный статический метод M3; частный статический метод M2; static {try {m1 = class.forname ("java.lang.object"). getmethod ("equals", new class [] {class.forname ("java.lang.object")}); m0 = class.forname ("java.lang.object"). getmethod ("hashcode", новый класс [0]); m3 = class.forname ("***. RealSubject"). getMethod ("запрос", новый класс [0]); m2 = class.forname ("java.lang.object"). getMethod ("toString", новый класс [0]); } catch (nosuchmethodexception nosuchmethodexception) {бросить новый nosuchmethoderror (nosuchmethodexception.getmessage ()); } catch (classnotfoundexception classnotfoundexception) {бросить новый noclassdeffounderror (classnotfoundexception.getmessage ()); }} // static public $ proxy0 (volcocationhandler vlocationhandler) {super (vocotichandler); } @Override public final boolean equals (Object obj) {try {return ((boolean) super.h.invoke (this, m1, new Object [] {obj})) .booleanValue (); } catch (бросаемый) {бросить новый UndEclaredThableException (Throwable); }} @Override public final int hashcode () {try {return ((integer) super.h.invoke (this, m0, null)). Intvalue (); } catch (бросаемый) {бросить новый UndEclaredThableException (Throwable); }} public final void request () {try {super.h.invoke (this, m3, null); возвращаться; } catch (error e) {} catch (throwable throwable) {выбрасывает новый UndeclareRowableException (Throwable); }} @Override public final String toString () {try {return (string) super.h.invoke (this, m2, null); } catch (бросаемый) {бросить новый UndEclaredThableException (Throwable); }}}Затем выпустите полученный экземпляр $ proxy0 в субъект и назначите ссылку на субъект. Когда метод субъекта. Request () выполняется, метод запроса () в классе $ proxy0 вызывается, и метод invoke () h в прокси -последовательности родительского класса. То есть vococationhandler.invoke ().
PS: 1. Отнесее отметить, что метод getProxyclass в классе прокси возвращает класс класса прокси. Причина этого в том, что в начале я совершил ошибку низкого уровня, думая, что возврат-это «класс класса прокси»-! Рекомендуется взглянуть на исходный код getProxyclass, который очень длинный =. =
2. Из исходного кода $ proxy0 можно увидеть, что динамический класс прокси не только прокси методов на отображении границы раздела, но и прокси унаследованные три метода equals (), hashcode () и tostring () в объекте класса корневого класса Java и только эти три метода.
Q: Пока что еще есть вопрос. Первый параметр в методе Invoke является экземпляром прокси (если точнее, экземпляр $ proxy0 наконец -то используется), но что такое использование? Или как функция появляется в программе?
A: С моего текущего уровня этот параметр прокси не имеет никакого эффекта. Во всем динамическом прокси -механизме параметр прокси метода Invoke в InvocationHandler не используется. Перепущенный параметр на самом деле является экземпляром прокси -класса. Я думаю, что это могло бы позволить программистам использовать отражение в методе Invoke, чтобы получить некоторую информацию о классе прокси.
Суммировать
Выше приведено все содержание этой статьи о методе Invoke () в InvocationHandler. Я надеюсь, что это будет полезно для всех. Заинтересованные друзья могут продолжать ссылаться на этот сайт:
Подробное объяснение пружинного статического прокси и динамического прокси -кода
Пример метода впрыска в рамках Spring Framework
Реализация программирования Java SpringMVC простого входа в систему
Если есть какие -либо недостатки, пожалуйста, оставьте сообщение, чтобы указать это.