Класс 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класса-прокси такой же, как у системных классов, загруженных загрузчиком bootstrap-классов, таких какjava.lang.Object, потому что код для класса-прокси генерируется надёжным системным кодом. Эта область защиты обычно получаетjava.security.AllPermission.- Метод
Proxy.isProxyClassможет использоваться для определения того, является ли данный класс классом-прокси.
Экземпляр-прокси имеет следующие свойства:
- Для данного экземпляра-прокси
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.
Принадлежность пакета и модуля к классу-прокси
Пакет и модуль, к которым принадлежит класс-прокси, выбираются таким образом, чтобы доступность класса-прокси соответствовала доступности прокси-интерфейсов. Конкретно, принадлежность пакета и модуля к классу-прокси, определённому методамиgetProxyClass(ClassLoader, Class[]) или newProxyInstance(ClassLoader, Class[], InvocationHandler), определяется следующим образом: - Если все прокси-интерфейсы находятся в пакетах, отмеченных как экспортируемые или открытые:
- Если все прокси-интерфейсы являются публичными, то класс-прокси является публичным в пакете, экспортированном беспредельным модулем (unnamed module) указанного загрузчика. Имя пакета не определено.
- Если хотя бы один из всех прокси-интерфейсов является непубличным, то класс-прокси является непубличным в пакете и модуле непубличных интерфейсов. Все непубличные интерфейсы должны находиться в одном пакете и модуле; в противном случае создание прокси невозможно. невозможно.
- Если хотя бы один прокси-интерфейс находится в пакете, который неэкспортируемый и неоткрытый:
- Если все прокси-интерфейсы являются публичными, то класс-прокси является публичным в неэкспортируемом, неооткрытом пакете динамического модуля. Имена пакета и модуля не определены.
- Если хотя бы один из всех прокси-интерфейсов является непубличным, то класс-прокси является непубличным в пакете и модуле непубличных интерфейсов. Все непубличные интерфейсы должны находиться в одном пакете и модуле; в противном случае создание прокси невозможно. невозможно.
Обратите внимание, что если прокси-интерфейсы с различными уровнями доступа — например, экспортируемый публичный интерфейс и неэкспортируемый непубличный интерфейс — проксируются одним экземпляром, то доступность класса-прокси определяется наименее доступным прокси-интерфейсом.
Обратите внимание, что произвольный код может получить доступ к классу-прокси в открытом пакете с помощью 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 может выбрасывать только типы исключений checked, приводимые к одному из типов исключений в пункте throws метода во всех прокси-интерфейсах, через которые он может быть вызван. Если метод invoke выбрасывает исключение checked, которое не приводимо ни к одному из типов исключений, объявленных в методе одного из прокси-интерфейсов, через который он может быть вызван, то необработанное исключение UndeclaredThrowableException будет выброшено в вызове на экземпляре-прокси. Это ограничение означает, что не все типы исключений, возвращённые при вызове getExceptionTypes на объекте Method , переданном методу invoke , обязательно могут быть успешно выброшены методом invoke.
- С момента:
- 1.3
- См. также:
-
InvocationHandler, Сериализованная форма
Поля
| Модификатор и тип | Поле | Описание |
|---|---|---|
protected InvocationHandler | h | обработчик вызовов для этого экземпляра прокси. |
Конструкторы
| Модификатор | Конструктор | Описание |
|---|---|---|
protected | Proxy(InvocationHandler h) | Создает новый экземпляр |
Методы
| Модификатор и тип | Метод | Описание |
|---|---|---|
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, 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.
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/reflect/Proxy.html