Вопрос по java, cglib, reflection, dynamic-proxy – В чем разница между динамическим прокси JDK и CGLib?

114

В случаеProxy Design Pattern, В чем разница междуДинамический прокси JDK и сторонние API генерации динамического кода, такие какCGLIB?

В чем разница между использованием обоих подходов и когда один предпочитает один другому?

Получите код здесь: & lt;gist.github.com/ksauzz/1563486& GT ;. В cglib вы можете создать как прокси класса, так и интерфейсный прокси. Spring по умолчанию использует CGlib, а AspectJ использует прокси Java. Прочитайте это также:jnb.ociweb.com/jnb/jnbNov2005.html ;) Subhadeep Ray

Ваш Ответ

4   ответа
19

Dynamic proxy: Динамические реализации интерфейсов во время выполнения с использованиемJDK Reflection API.

Example: Spring использует динамические прокси для транзакций следующим образом:

enter image description here

Сгенерированный прокси приходит поверх bean-компонента. Это добавляет транснациональное поведение к бобу. До того, как прокси-сервер генерирует динамически во время выполнения, используя JDK Reflection API.

Когда приложение остановлено, прокси будет уничтожен, и у нас будет только интерфейс и бин в файловой системе.

В приведенном выше примере у нас есть интерфейс. Но в большинстве случаев реализация интерфейса не самая лучшая. Таким образом, bean-компонент не реализует интерфейс, в этом случае мы используем наследование:

enter image description here

Для генерации таких прокси Spring использует стороннюю библиотеку под названиемCGLib.

CGLib (CодаGenerationLibrary) построен поверхКАК М, это главным образом используется для создания компонента расширения прокси и добавляет поведение компонента в методы прокси.

Примеры для JDK Динамический прокси и CGLib

Весенний реф

152

этому ваш целевой класс должен реализовать интерфейс, который затем также реализуется прокси-классом).

CGLIB (и javassist) могут создавать прокси путем создания подклассов. В этом случае прокси становится подклассом целевого класса. Нет необходимости в интерфейсах.

Таким образом, прокси-серверы Java Dynamic могут использовать прокси:public class Foo implements iFoo где CGLIB может прокси:public class Foo

РЕДАКТИРОВАТЬ:

Я должен упомянуть, что, поскольку javassist и CGLIB используют прокси посредством подклассов, это является причиной, по которой вы не можете объявлять финальные методы или делать класс финальным при использовании каркасов, которые полагаются на это. Это помешало бы этим библиотекам создавать подклассы для вашего класса и переопределять ваши методы.

cglib не может проксировать финальные методы, но не будет выдавать исключениеgist.github.com/mhewedy/7345403cfa52e6f47563f8a204ec0e80
Спасибо..!! но было бы полезно, если бы вы могли дать мне один пример кода (или ссылку), чтобы проиллюстрировать использование одного над другим в некоторых случаях ... !!! KDjava
код CGLIB-edc4it.com/2011/03/01/… было действительно интересно и полезно тоже .. Большое спасибо. !! KDjava
Следует также отметить, что создание подкласса CGLib требует достаточных знаний о суперклассе, чтобы иметь возможность вызывать правильный конструктор с правильными аргументами. В отличие от интерфейсного прокси, который не заботится о конструкторах. Это делает работу с прокси-серверами CGLib менее «автоматической». чем прокси JDK. Другое различие заключается в «стеке» Стоимость. JDK-прокси всегда получает дополнительные кадры стека за вызов, в то время как CGLib может не стоить дополнительных кадров стека. Это становится все более актуальным, чем сложнее становится приложение (поскольку чем больше стек, тем больше потоков памяти потребляют).
Обратите внимание, что прокси-серверы JDK фактически используют прокси для IFoo, а не для любого типа Foo. Это довольно важное различие. Кроме того, прокси-серверы cglib являются полными подклассами - воспользуйтесь этим! Используйте фильтры только для тех прокси-методов, которые вам нужны, и напрямую используйте сгенерированный класс
44

Differences in functionality

The JDK proxies allow to implement any set of interfaces while subclassing java.lang.reflect.Proxy. Any interface method, plusObject::hashCode, Object::equals and Object::toString is then forwarded to an InvocationHandler.

cglib allows you to implement any set of interfaces while subclassing any non-final class. Also, methods can be overridden optionally, i.e. not all non-abstract methods need to be intercepted. Furthermore, there are different ways of implementing a method. It also offers an InvocationHandler class (in a different package), but it also allows to call super methods by using more advanced interceptors as for example a MethodInterceptor. Furthermore, cglib can improve performance by specialized interceptions like FixedValue. I once wrote a summary of different interceptors for cglib.

Performance differences

Прокси JDK реализованы довольно наивно только с одним диспетчером перехвата,InvocationHandler, Это требует отправки виртуального метода в реализацию, которая не всегда может быть встроена. Cglib позволяет создавать специализированный байт-код, который иногда может повысить производительность. Вот некоторые сравнения для реализации интерфейса с 18 методами-заглушками:

            cglib                   JDK proxy
creation    804.000     (1.899)     973.650     (1.624)
invocation    0.002     (0.000)       0.005     (0.000)

Время указывается в наносекундах со стандартным отклонением в фигурных скобках. Вы можете найти более подробную информацию о тесте вБайт Бадди учебникгде Byte Buddy - более современная альтернатива cglib. Также обратите внимание, что cglib больше не находится в активной разработке.

Если вы вызываете метод для прокси-объекта, любой вызов направляется через наш обработчик вызовов. Если какой-либо обработчик вызова вызывает делегатов для вызова объекта, происходит упомянутая рекурсия.
This должен быть принятый ответ!
Cglib является внешней зависимостью и в настоящее время не поддерживается. Полагаться на стороннее программное обеспечение - всегда азартная игра, поэтому лучше всего, когда на него полагаются как можно меньше людей.
В своем блоге вы говорите: «Однако вы должны быть осторожны при вызове метода для прокси-объекта, который поставляется с методом InvocationHandler # invoke. Все вызовы этого метода будут отправлены с одним и тем же InvocationHandler и, следовательно, могут привести к бесконечному циклу. & Quot; Что вы имеете в виду?
Почему весенняя документация предпочитает JDK-прокси по сравнению с cglib, учитывая преимущества производительности последнего?docs.spring.io/spring/docs/2.5.x/reference/…
3

Из весенней документации :

Spring AOP uses either JDK dynamic proxies or CGLIB to create the proxy for a given target object. (JDK dynamic proxies are preferred whenever you have a choice).

If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used. All of the interfaces implemented by the target type will be proxied. If the target object does not implement any interfaces then a CGLIB proxy will be created.

If you want to force the use of CGLIB proxying (for example, to proxy every method defined for the target object, not just those implemented by its interfaces) you can do so. However, there are some issues to consider:

final methods cannot be advised, as they cannot be overriden.

You will need the CGLIB 2 binaries on your classpath, whereas dynamic proxies are available with the JDK. Spring will automatically warn you when it needs CGLIB and the CGLIB library classes are not found on the classpath.

The constructor of your proxied object will be called twice. This is a natural consequence of the CGLIB proxy model whereby a subclass is generated for each proxied object. For each proxied instance, two objects are created: the actual proxied object and an instance of the subclass that implements the advice. This behavior is not exhibited when using JDK proxies. Usually, calling the constructor of the proxied type twice, is not an issue, as there are usually only assignments taking place and no real logic is implemented in the constructor.

Похожие вопросы