Spec-Zone.ru › OpenJDK 8

Класс Proxy

  • java.lang.Object
    • java.lang.reflect.Proxy
Все реализованные интерфейсы:
Serializable

public class Proxy
extends Object
implements Serializable

Proxy предоставляет статические методы для создания динамических классов-прокси и экземпляров, а также является суперклассом всех динамических классов-прокси, созданных этими методами.

Для создания прокси для некоторого интерфейса Foo:

InvocationHandler handler = new MyInvocationHandler(...);
     Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
     Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
                     newInstance(handler);
или проще:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
                                          new Class<?>[] { Foo.class },
                                          handler);

Динамический класс-прокси (в дальнейшем просто класс-прокси) — это класс, реализующий список интерфейсов, указанных во время выполнения при создании класса, с поведением, описанным ниже. Интерфейс прокси — это такой интерфейс, который реализуется классом-прокси. Экземпляр прокси — это экземпляр класса-прокси. Каждый экземпляр прокси имеет связанный с ним объект обработчика вызовов, который реализует интерфейс InvocationHandler. Вызов метода на экземпляре прокси через один из его интерфейсов прокси будет перенаправлен на метод invoke обработчика вызовов экземпляра, передавая экземпляр прокси, объект java.lang.reflect.Method , определяющий метод, который был вызван, и массив типа Object содержащий аргументы. Обработчик вызовов обрабатывает закодированный вызов метода соответствующим образом, и результат, который он возвращает, будет возвращен как результат вызова метода на экземпляре прокси.

Класс-прокси имеет следующие свойства:

  • Классы-прокси являются общедоступными, final и не абстрактными, если все интерфейсы прокси являются общедоступными.
  • Классы-прокси являются не общедоступными, final и не абстрактными, если любой из интерфейсов прокси является неопределённым.
  • Неполное имя класса-прокси не определено. Однако пространство имён классов, начинающихся со строки "$Proxy" должно быть зарезервировано для классов-прокси.
  • Класс-прокси расширяет java.lang.reflect.Proxy.
  • Класс-прокси реализует ровно те интерфейсы, которые были указаны при его создании, в том же порядке.
  • Если класс-прокси реализует не общедоступный интерфейс, то он будет определён в той же папке, что и этот интерфейс. В противном случае, пакет класса-прокси также не определён. Обратите внимание, что уплотнение пакетов не помешает классу-прокси быть успешно определённым в определённом пакете во время выполнения, а также не помешают классы, уже определённые тем же загрузчиком классов и тем же пакетом с конкретными подписями.
  • Поскольку класс-прокси реализует все интерфейсы, указанные при его создании, вызов getInterfaces на его объекте Class вернёт массив, содержащий тот же список интерфейсов (в порядке, указанном при его создании), вызов getMethods на его объекте Class вернёт массив объектов Method, которые включают все методы в этих интерфейсах, и вызов getMethod найдёт методы в интерфейсах прокси, как и ожидалось.
  • Метод Proxy.isProxyClass вернёт true, если ему передан класс-прокси — класс, возвращаемый Proxy.getProxyClass или класс объекта, возвращаемого Proxy.newProxyInstance, и false в противном случае.
  • Домен защиты java.security.ProtectionDomain класса-прокси такой же, как и у системных классов, загруженных загрузчиком класса загрузки, таких как java.lang.Object, потому что код класса-прокси генерируется надёжным системным кодом. Этот домен защиты обычно будет предоставлен java.security.AllPermission.
  • Каждый класс-прокси имеет один общедоступный конструктор, который принимает один аргумент — реализацию интерфейса InvocationHandler, для установки обработчика вызовов для экземпляра прокси. Вместо того, чтобы использовать API рефлексии для доступа к общедоступному конструктору, экземпляр прокси также может быть создан путём вызова метода Proxy.newProxyInstance, который объединяет действия вызова Proxy.getProxyClass с вызовом конструктора с обработчиком вызовов.

Экземпляр прокси имеет следующие свойства:

  • Учитывая экземпляр прокси proxy и один из интерфейсов, реализованных его классом-прокси Foo, следующее выражение вернёт true:
    proxy instanceof Foo
    и следующее преобразование типа будет успешным (вместо выброса ClassCastException) :
    (Foo) proxy
  • Каждый экземпляр прокси имеет связанный с ним обработчик вызовов, тот, который был передан его конструктору. Статический метод Proxy.getInvocationHandler вернёт обработчик вызовов, связанный с экземпляром прокси, переданным в качестве аргумента.
  • Вызов метода интерфейса на экземпляре прокси будет закодирован и передан методу обработчика вызовов invoke, как описано в документации для этого метода.
  • Вызов методов hashCode, equals, или toString объявленных в java.lang.Object на экземпляре прокси будет закодирован и передан методу обработчика вызовов invoke аналогичным образом, как закодированы и перенаправлены вызовы методов интерфейса, как описано выше. Класс-объявление объекта Method , переданного invoke будет java.lang.Object. Другие общедоступные методы экземпляра прокси, унаследованные от java.lang.Object, не переопределяются классом-прокси, поэтому вызовы этих методов ведут себя так же, как и для экземпляров java.lang.Object.

Методы, дублирующиеся в нескольких интерфейсах прокси

Когда два или более интерфейса класса-прокси содержат метод с одинаковым именем и сигнатурой параметра, порядок интерфейсов класса-прокси становится существенным. При вызове такого метода-дубликата на экземпляре прокси, объект Method , переданный обработчику вызовов, не обязательно будет тем, чей объявляющий класс присваивается типу ссылки интерфейса, через который был вызван метод прокси. Это ограничение существует, потому что соответствующая реализация метода в сгенерированном классе-прокси не может определить, через какой интерфейс он был вызван. Поэтому, когда метод-дубликат вызывается на экземпляре прокси, объект Method для метода в главном интерфейсе, содержащем метод (либо напрямую, либо через супер-интерфейс), в списке интерфейсов класса-прокси передаётся обработчику вызовов invoke методу, независимо от типа ссылки, через который произошёл вызов метода.

Если интерфейс прокси содержит метод с таким же именем и сигнатурой параметра, как методы hashCode, equals, или toString класса java.lang.Object, при вызове такого метода на экземпляре прокси, объект Method , переданный обработчику вызовов, будет иметь java.lang.Object в качестве объявляющего класса. Другими словами, общедоступные, не-final методы java.lang.Object логически предшествуют всем интерфейсам прокси для определения, какой объект Method передать обработчику вызовов.

Также обратите внимание, что при перенаправлении дублирующегося метода обработчику вызовов, метод invoke может выбрасывать только типы проверенных исключений, которые присваиваются одному из типов исключений в throws пункте метода во всех интерфейсах прокси, через которые он может быть вызван. Если метод invoke выбрасывает проверенное исключение, которое не присваивается ни одному из типов исключений, объявленных методом в одном из интерфейсов прокси, через которые он может быть вызван, то не проверенное исключение UndeclaredThrowableException будет выброшено вызовом на экземпляре прокси. Это ограничение означает, что не все типы исключений, возвращённые вызовом getExceptionTypes на объекте Method , переданном методу invoke, могут быть успешно выброшены методом invoke.

С момента:
1.3
См. также:
InvocationHandler, Сериализованная форма

Поля

Модификатор и тип Поле и описание
protected InvocationHandler h

обработчик вызовов для данного экземпляра прокси.

Конструкторы

Модификатор Конструктор и описание
protected Proxy(InvocationHandler h)

Создаёт новый экземпляр Proxy из подкласса (как правило, динамического класса-прокси) со значением для его обработчика вызовов.

Методы

Модификатор и тип Метод и описание
static InvocationHandler getInvocationHandler(Object proxy)

Возвращает обработчик вызовов для указанного экземпляра прокси.

static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)

Возвращает объект java.lang.Class для класса-прокси, заданного загрузчиком классов и массивом интерфейсов.

static boolean isProxyClass(Class<?> cl)

Возвращает true тогда и только тогда, когда указанный класс был динамически сгенерирован как класс-прокси, используя метод getProxyClass или метод newProxyInstance.

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

Возвращает экземпляр класса-прокси для указанных интерфейсов, который перенаправляет вызовы методов на указанный обработчик вызовов.

Методы унаследованные от класса java.lang.Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Поля

h

protected InvocationHandler h

обработчик вызовов для данного экземпляра прокси.

Конструкторы

Proxy

protected Proxy(InvocationHandler h)

Создаёт новый Proxy экземпляр из подкласса (обычно, динамический класс прокси) со значением обработчика вызовов.

Параметры:
h - обработчик вызовов для данного экземпляра прокси
Исключения:
NullPointerException - если заданный обработчик вызовов, h, является null.

Методы

getProxyClass

public static Class<?> getProxyClass(ClassLoader loader,
                                     Class<?>... interfaces)
                              throws IllegalArgumentException

Возвращает объект java.lang.Class для класса прокси, заданного загрузчиком классов и массивом интерфейсов. Класс прокси будет определён заданным загрузчиком классов и будет реализовывать все указанные интерфейсы. Если какой-либо из указанных интерфейсов является непубличным, то класс прокси также будет непубличным. Если класс прокси для такой же комбинации интерфейсов уже был определён загрузчиком классов, то будет возвращён существующий класс прокси; в противном случае, класс прокси для этих интерфейсов будет сгенерирован динамически и определён загрузчиком классов.

Существует несколько ограничений на параметры, которые могут быть переданы в Proxy.getProxyClass:

  • Все объекты Class в массиве interfaces должны представлять интерфейсы, а не классы или примитивные типы.
  • Никакие два элемента в массиве interfaces не должны ссылаться на идентичные объекты Class.
  • Все типы интерфейсов должны быть видимы по имени через указанный загрузчик классов. Другими словами, для загрузчика классов cl и каждого интерфейса i, следующее выражение должно быть истинным:
    Class.forName(i.getName(), false, cl) == i
  • Все непубличные интерфейсы должны быть в одном пакете; иначе невозможно, чтобы класс прокси реализовывал все интерфейсы, независимо от того, в каком пакете он определён.
  • Для любой совокупности методов членов указанных интерфейсов, имеющих одинаковый сигнатур:
    • Если тип возвращаемого значения любого из методов — примитивный тип или void, то все методы должны иметь тот же тип возвращаемого значения.
    • В противном случае, тип возвращаемого значения одного из методов должен быть приводимым к типам возвращаемого значения всех остальных методов.
  • Полученный класс прокси не должен превышать никаких ограничений, накладываемых на классы виртуальной машиной. Например, ВМ может ограничить количество интерфейсов, которые может реализовать класс, до 65535; в этом случае размер массива interfaces не должен превышать 65535.

Если какое-либо из этих ограничений нарушено, Proxy.getProxyClass выбросит исключение IllegalArgumentException. Если аргумент interfaces или любой из его элементов является null, будет выброшено исключение NullPointerException.

Обратите внимание, что порядок указанных интерфейсов прокси важен: два запроса на класс прокси с одинаковой комбинацией интерфейсов, но в разном порядке, приведут к двум различным классам прокси.

Параметры:
loader - загрузчик классов для определения класса прокси
interfaces - список интерфейсов для реализации классом прокси
Возвращаемое значение:
класс прокси, который определён в указанном загрузчике классов и реализует указанные интерфейсы
Исключения:
IllegalArgumentException - если какое-либо из ограничений на параметры, которые могут быть переданы в getProxyClass, нарушено
SecurityException - если присутствует менеджер безопасности, s, и выполняется любое из следующих условий:
  • заданный loader является null, и загрузчик класса вызывающего метода не является null, и вызов s.checkPermission с правом RuntimePermission("getClassLoader") отклоняет доступ.
  • для каждого интерфейса прокси, intf, загрузчик класса вызывающего метода не совпадает с загрузчиком класса для intf или не является его предком, и вызов s.checkPackageAccess() отклоняет доступ к intf.
NullPointerException - если аргумент массива interfaces или любой из его элементов являются null

newProxyInstance

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
                               throws IllegalArgumentException

Возвращает экземпляр класса прокси для указанных интерфейсов, который перенаправляет вызовы методов заданному обработчику вызовов.

Proxy.newProxyInstance выбросит исключение IllegalArgumentException по тем же причинам, что и Proxy.getProxyClass.

Параметры:
loader - загрузчик классов для определения класса прокси
interfaces - список интерфейсов для реализации классом прокси
h - обработчик вызовов для перенаправления вызовов методов
Возвращаемое значение:
экземпляр прокси с заданным обработчиком вызовов класса прокси, определённого указанным загрузчиком классов и реализующего указанные интерфейсы
Исключения:
IllegalArgumentException - если какое-либо из ограничений на параметры, которые могут быть переданы в getProxyClass, нарушено
SecurityException - если менеджер безопасности, s, присутствует и выполняется любое из следующих условий:
  • заданный loader является null, и загрузчик класса вызывающего метода не является null, и вызов s.checkPermission с правом RuntimePermission("getClassLoader") отклоняет доступ;
  • для каждого интерфейса прокси, intf, загрузчик класса вызывающего метода не совпадает с загрузчиком класса для intf или не является его предком, и вызов s.checkPackageAccess() отклоняет доступ к intf;
  • любой из заданных интерфейсов прокси является непубличным, и класс вызывающего метода не находится в том же пакете выполнения, что и непубличный интерфейс, и вызов s.checkPermission с правом ReflectPermission("newProxyInPackage.{package name}") отклоняет доступ.
NullPointerException - если аргумент массива interfaces или любой из его элементов является null, или если обработчик вызовов, h, является null

isProxyClass

public static boolean isProxyClass(Class<?> cl)

Возвращает true тогда и только тогда, когда указанный класс был динамически сгенерирован как класс прокси с помощью метода getProxyClass или метода newProxyInstance.

Надёжность этого метода важна для возможности использования его для принятия решений о безопасности, поэтому его реализация не должна просто проверять, расширяет ли рассматриваемый класс Proxy.

Параметры:
cl - класс для проверки
Возвращаемое значение:
true если класс является классом прокси и false в противном случае
Исключения:
NullPointerException - если cl является null

getInvocationHandler

public static InvocationHandler getInvocationHandler(Object proxy)
                                              throws IllegalArgumentException

Возвращает обработчик вызовов для указанного экземпляра прокси.

Параметры:
proxy - экземпляр прокси, для которого требуется получить обработчик вызовов
Возвращаемое значение:
обработчик вызовов для экземпляра прокси
Исключения:
IllegalArgumentException - если аргумент не является экземпляром прокси
SecurityException - если менеджер безопасности, s, присутствует и загрузчик класса вызывающего метода не совпадает с загрузчиком класса обработчика вызовов или не является его предком, и вызов s.checkPackageAccess() отклоняет доступ к классу обработчика вызовов.

© 1993, 2020, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API