Spec-Zone.ru › OpenJDK 21

Класс 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
     
    , и следующая операция приведения типов будет успешной (вместо выброса исключения %%%CODE_BLOCK_26%%):
         (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.

С момента:
1.3
См. также:
  • 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;
  • любой из заданных интерфейсов прокси не является общедоступным и класс вызывающего не находится в том же пакете выполнения, что и не общедоступный интерфейс, и вызов 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, 2023, 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/21/docs/api/java.base/java/lang/reflect/Proxy.html

Spec-Zone.ru

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