의 경우 프록시 디자인 패턴 의 차이 무엇입니까 JDK의 다이내믹 프록시 및 타사 동적 코드 생성 API의 같은 CGLIB는 ?
두 가지 접근 방식을 사용하는 것과 언제 서로를 선호해야 하는가?
의 경우 프록시 디자인 패턴 의 차이 무엇입니까 JDK의 다이내믹 프록시 및 타사 동적 코드 생성 API의 같은 CGLIB는 ?
두 가지 접근 방식을 사용하는 것과 언제 서로를 선호해야 하는가?
답변:
JDK Dynamic 프록시는 인터페이스별로 만 프록시 할 수 있습니다 (따라서 대상 클래스는 인터페이스를 구현해야하며이 인터페이스는 프록시 클래스에 의해 구현됩니다).
CGLIB (및 javassist)는 서브 클래 싱으로 프록시를 작성할 수 있습니다. 이 시나리오에서 프록시는 대상 클래스의 서브 클래스가됩니다. 인터페이스가 필요 없습니다.
따라서 Java Dynamic 프록시는 프록시 할 수 있습니다. public class Foo implements iFoo
여기서 CGLIB는 프록시 할 수 있습니다.public class Foo
편집하다:
javassist와 CGLIB는 서브 클래 싱에 의해 프록시를 사용하기 때문에 이것이 최종 프레임 워크를 사용할 때 최종 메소드를 선언하거나 클래스를 최종적으로 만들 수없는 이유입니다. 이렇게하면 라이브러리가 클래스를 서브 클래스 화하고 메소드를 재정의하는 것을 막을 수 있습니다.
기능상의 차이점
JDK 프록시를 사용하면 서브 클래 싱하는 동안 인터페이스 세트를 구현할 수 Object
있습니다. 모든 인터페이스 방법은, 플러스 Object::hashCode
, Object::equals
그리고 Object::toString
다음으로 전달됩니다 InvocationHandler
. 또한 표준 라이브러리 인터페이스 java.lang.reflect.Proxy
가 구현됩니다.
cglib를 사용하면 최종 클래스가 아닌 클래스를 서브 클래 싱하면서 인터페이스 세트를 구현할 수 있습니다. 또한, 방법은 선택적으로 재정의 될 수 있으며, 즉 모든 비 추상적 방법이 차단 될 필요는 없다. 또한 메소드를 구현하는 다른 방법이 있습니다. 또한 InvocationHandler
다른 패키지 의 클래스를 제공 하지만 a와 같이 고급 인터셉터를 사용하여 수퍼 메소드를 호출 할 수도 있습니다 MethodInterceptor
. 또한 cglib는와 같은 특수한 차단으로 성능을 향상시킬 수 있습니다 FixedValue
. 한 번 cglib에 대한 다른 인터셉터 요약을 작성 했습니다 .
성능 차이
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의 자습서 에서 Byte Buddy가 cglib의보다 현대적인 대안 인 벤치 마크에 대한 자세한 내용을 확인할 수 있습니다 . 또한 cglib는 더 이상 개발 중이 아닙니다.
동적 프록시 : JDK Reflection API를 사용하여 런타임시 인터페이스의 동적 구현 .
예 : Spring은 다음과 같이 트랜잭션에 동적 프록시를 사용합니다.
생성 된 프록시는 Bean의 맨 위에옵니다. Bean에 다국적 동작을 추가합니다. 여기서 프록시는 JDK Reflection API를 사용하여 런타임에 동적으로 생성됩니다.
응용 프로그램이 중지되면 프록시가 삭제되고 파일 시스템에 인터페이스와 Bean 만 있습니다.
위의 예에서 인터페이스가 있습니다. 그러나 대부분의 인터페이스 구현은 최선이 아닙니다. 따라서 bean은 인터페이스를 구현하지 않습니다.이 경우 상속을 사용합니다.
이러한 프록시를 생성하기 위해 Spring은 CGLib 이라는 타사 라이브러리를 사용합니다 .
CGLIB ( C ODE G eneration 리브 rary)는 상단에 구축 ASM 이 주로 프록시 연장 빈을 생성하고 프록시 방법 콩 동작을 추가 사용된다.
Spring AOP는 JDK 동적 프록시 또는 CGLIB를 사용하여 지정된 대상 오브젝트에 대한 프록시를 작성합니다. (선택할 때마다 JDK 동적 프록시가 선호됩니다).
프록시 할 대상 객체가 하나 이상의 인터페이스를 구현하는 경우 JDK 동적 프록시가 사용됩니다. 대상 유형으로 구현 된 모든 인터페이스가 프록시됩니다. 대상 객체가 인터페이스를 구현하지 않으면 CGLIB 프록시가 작성됩니다.
CGLIB 프록 싱을 강제로 사용하려면 (예를 들어, 인터페이스로 구현 된 메소드뿐만 아니라 대상 오브젝트에 대해 정의 된 모든 메소드를 프록 싱하기 위해) 그렇게 할 수 있습니다. 그러나 고려해야 할 몇 가지 문제가 있습니다.
재정의 될 수 없으므로 최종 방법은 권장되지 않습니다.
클래스 경로에 CGLIB 2 바이너리가 필요하지만 JDK와 함께 동적 프록시를 사용할 수 있습니다. Spring은 CGLIB가 필요하고 CGLIB 라이브러리 클래스가 클래스 경로에 없을 때 자동으로 경고합니다.
프록시 된 객체의 생성자가 두 번 호출됩니다. 이는 각 프록시 오브젝트마다 서브 클래스가 생성되는 CGLIB 프록시 모델의 자연스러운 결과입니다. 프록시 된 각 인스턴스에 대해 실제 프록시 된 오브젝트와 권고를 구현하는 서브 클래스의 두 개의 오브젝트가 작성됩니다. JDK 프록시를 사용할 때는이 동작이 나타나지 않습니다. 일반적으로 할당 유형 만 생성되고 생성자에 실제 논리가 구현되지 않으므로 프록시 유형의 생성자를 두 번 호출하는 것은 문제가되지 않습니다.