Spec-Zone.ru › OpenJDK 17

Класс Proxy

java.lang.Object
java.lang.reflect.Proxy
Все реализованные интерфейсы:
Serializable
public class Proxy extends Object implements Serializable
Proxy предоставляет статические методы для создания объектов, которые ведут себя как экземпляры интерфейсов, но позволяют настраивать вызов методов. Для создания прокси-экземпляра для некоторого интерфейса Foo:

     InvocationHandler handler = new MyInvocationHandler(...);
     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
                                          new Class<?>[] { Foo.class },
                                          handler);
 

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

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

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

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

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

Членство пакета и модуля класса-прокси

Пакет и модуль, к которым принадлежит класс-прокси, выбираются таким образом, чтобы доступность класса-прокси соответствовала доступности прокси-интерфейсов. В частности, членство пакета и модуля класса-прокси, определённого методами getProxyClass(ClassLoader, Class[]) или newProxyInstance(ClassLoader, Class[], InvocationHandler), задаётся следующим образом:
  1. Если все прокси-интерфейсы находятся в экспортированных или открытых пакетах:
    1. Если все прокси-интерфейсы публичные, то класс-прокси является публичным в безусловно экспортированном, но не открытом пакете. Имя пакета и модуля не указаны.
    2. Если хотя бы один из всех прокси-интерфейсов не публичный, то класс-прокси является не публичным в пакете и модуле непубличных интерфейсов. Все непубличные интерфейсы должны быть в одном пакете и модуле; в противном случае их проксирование невозможно.
  2. Если хотя бы один прокси-интерфейс находится в пакете, который является неэкспортированным и неоткрытым:
    1. Если все прокси-интерфейсы публичные, то класс-прокси является публичным в неэкспортированном, неоткрытом пакете динамического модуля. Имена пакета и модуля не указаны.
    2. Если хотя бы один из всех прокси-интерфейсов не публичный, то класс-прокси является не публичным в пакете и модуле непубличных интерфейсов. Все непубличные интерфейсы должны быть в одном пакете и модуле; в противном случае их проксирование невозможно.

Обратите внимание, что если прокси-интерфейсы с разной доступностью — например, экспортированный публичный интерфейс и неэкспортированный непубличный интерфейс — проксируются одним экземпляром, то доступность класса-прокси регулируется наименее доступным прокси-интерфейсом.

Обратите внимание, что произвольный код может получить доступ к классу-прокси в открытом пакете с помощью setAccessible, тогда как класс-прокси в неоткрытом пакете никогда не доступен коду за пределами модуля класса-прокси.

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

Динамические модули

Динамический модуль — это именованный модуль, генерируемый во время выполнения. Класс-прокси, определённый в динамическом модуле, изолирован и недоступен для какого-либо модуля. Вызов Constructor.newInstance(Object...) на классе-прокси в динамическом модуле выбросит IllegalAccessException; необходимо использовать метод Proxy.newProxyInstance.

Динамический модуль может читать модули всех суперинтерфейсов класса-прокси и модули классов и интерфейсов, на которые ссылаются все публичные сигнатуры методов класса-прокси. Если суперинтерфейс или ссылающийся класс или интерфейс, например, T, находится в неэкспортированном пакете, модуль T обновляется, чтобы экспортировать пакет T в динамический модуль.

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

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

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

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

Since:
1.3
See Also:
  • InvocationHandler
  • Сериализованная форма

Краткое описание полей

Модификатор и тип Поле Описание
protected InvocationHandler h
обработчик вызовов для этого прокси-объекта.

Краткое описание конструкторов

Proxy(InvocationHandler h)
Модификатор Конструктор Описание
protected
Создаёт новый Proxy экземпляр из подкласса (обычно, динамический прокси-класс) с указанным значением для обработчика вызовов.

Краткое описание методов

Модификатор и тип Метод Описание
static InvocationHandler getInvocationHandler(Object proxy)
Возвращает обработчик вызовов для указанного прокси-объекта.
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)
Устарело.
Прокси-классы, сгенерированные в именованном модуле, инкапсулированы и недоступны для кода за пределами этого модуля.
static boolean isProxyClass(Class<?> cl)
Возвращает true, если данный класс является прокси-классом.
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

@Deprecated public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException
Устарело.
Классы прокси, сгенерированные в именованном модуле, инкапсулированы и недоступны коду за пределами модуля. Constructor.newInstance будет выбрасывать IllegalAccessException при вызове на недоступном классе прокси. Используйте newProxyInstance(ClassLoader, Class[], InvocationHandler) для создания экземпляра прокси вместо этого.
Возвращает объект java.lang.Class для класса прокси, заданного загрузчиком классов и массивом интерфейсов. Класс прокси будет определён заданным загрузчиком классов и будет реализовывать все предоставленные интерфейсы. Если любой из заданных интерфейсов не является общедоступным, класс прокси будет недоступным. Если класс прокси для той же комбинации интерфейсов уже определён загрузчиком классов, то возвращается существующий класс прокси; в противном случае динамически генерируется класс прокси для этих интерфейсов и определяется загрузчиком классов.
Параметры:
loader - загрузчик классов для определения класса прокси
interfaces - список интерфейсов для реализации классом прокси
Возвращает:
класс прокси, который определён в заданном загрузчике классов и реализует заданные интерфейсы
Исключения:
IllegalArgumentException - если нарушены какие-либо из ограничений на параметры
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)
Возвращает экземпляр прокси для указанных интерфейсов, перенаправляющий вызовы методов к указанному обработчику вызовов.

IllegalArgumentException будет выброшено, если нарушено любое из следующих ограничений:

  • Все объекты Class в заданном массиве interfaces должны представлять собой нескрытые и незапечатанные интерфейсы, а не классы или примитивные типы.
  • Ни два элемента в массиве interfaces не должны ссылаться на одинаковые объекты Class.
  • Все типы интерфейсов должны быть видны по имени через указанный загрузчик классов. Другими словами, для загрузчика классов cl и каждого интерфейса i, следующее выражение должно быть истинным:

    Class.forName(i.getName(), false, cl) == i

  • Все типы, на которые ссылаются все общедоступные сигнатуры методов указанных интерфейсов и унаследованные их супер-интерфейсами, должны быть видны по имени через указанный загрузчик классов.
  • Все не-общедоступные интерфейсы должны находиться в одном пакете и модуле, определённых заданным загрузчиком классов, и модуль не-общедоступных интерфейсов может получить доступ ко всем типам интерфейсов; в противном случае для класса прокси не было бы возможности реализовать все интерфейсы, независимо от того, в каком пакете он определён.
  • Для любого набора методов-членов указанных интерфейсов, имеющих одинаковый сигнатуру:
    • Если тип возвращаемого значения любого из методов является примитивным типом или void, то все методы должны иметь тот же тип возвращаемого значения.
    • В противном случае, один из методов должен иметь тип возвращаемого значения, приводимый к типу возвращаемого значения всех остальных методов.
  • Получившийся класс прокси не должен превышать никаких ограничений, накладываемых на классы виртуальной машиной. Например, ВМ может ограничить количество интерфейсов, которые может реализовать класс, до 65535; в этом случае размер массива interfaces не должен превышать 65535.

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

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

isProxyClass

public static boolean isProxyClass(Class<?> cl)
Возвращает true, если данный класс является классом прокси.
Примечание об реализации:
Надёжность этого метода важна для возможности использования его для принятия решений о безопасности, поэтому его реализация не должна просто проверять, является ли класс-кандидат подклассом Proxy.
Параметры:
cl - класс для проверки
Возвращает:
true если класс является классом прокси и false в противном случае
Исключения:
NullPointerException - если cl является null

getInvocationHandler

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

© 1993, 2021, 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.
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/reflect/Proxy.html

Spec-Zone.ru

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