[java] JDK 동적 프록시와 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 이 주로 프록시 연장 빈을 생성하고 프록시 방법 콩 동작을 추가 사용된다.

JDK 동적 프록시 및 CGLib의 예

봄 심판


답변

Spring 문서에서 :

Spring AOP는 JDK 동적 프록시 또는 CGLIB를 사용하여 지정된 대상 오브젝트에 대한 프록시를 작성합니다. (선택할 때마다 JDK 동적 프록시가 선호됩니다).

프록시 할 대상 객체가 하나 이상의 인터페이스를 구현하는 경우 JDK 동적 프록시가 사용됩니다. 대상 유형으로 구현 된 모든 인터페이스가 프록시됩니다. 대상 객체가 인터페이스를 구현하지 않으면 CGLIB 프록시가 작성됩니다.

CGLIB 프록 싱을 강제로 사용하려면 (예를 들어, 인터페이스로 구현 된 메소드뿐만 아니라 대상 오브젝트에 대해 정의 된 모든 메소드를 프록 싱하기 위해) 그렇게 할 수 있습니다. 그러나 고려해야 할 몇 가지 문제가 있습니다.

재정의 될 수 없으므로 최종 방법은 권장되지 않습니다.

클래스 경로에 CGLIB 2 바이너리가 필요하지만 JDK와 함께 동적 프록시를 사용할 수 있습니다. Spring은 CGLIB가 필요하고 CGLIB 라이브러리 클래스가 클래스 경로에 없을 때 자동으로 경고합니다.

프록시 된 객체의 생성자가 두 번 호출됩니다. 이는 각 프록시 오브젝트마다 서브 클래스가 생성되는 CGLIB 프록시 모델의 자연스러운 결과입니다. 프록시 된 각 인스턴스에 대해 실제 프록시 된 오브젝트와 권고를 구현하는 서브 클래스의 두 개의 오브젝트가 작성됩니다. JDK 프록시를 사용할 때는이 동작이 나타나지 않습니다. 일반적으로 할당 유형 만 생성되고 생성자에 실제 논리가 구현되지 않으므로 프록시 유형의 생성자를 두 번 호출하는 것은 문제가되지 않습니다.


답변