AOP의 개념
AOP : Aspect-Oriented 프로그래밍 (단면 지향 프로그래밍)에서 Wikipedia는 다음과 같이 설명합니다. 측면은 물체, 클래스 또는 기능에 흩어져있는 단면적 문제를 설명하는 데 사용되는 새로운 모듈 식 메커니즘입니다. 문제에서 단면 문제를 분리하는 것은 탄젠트 지향 프로그래밍의 핵심 개념입니다. 초점을 분리하면 비즈니스 로직과 무관하게 특정 도메인 문제를 해결하는 코드가됩니다. 비즈니스 코드에는 특정 도메인 문제에 대한 코드에 대한 통화가 포함되어 있지 않습니다. 비즈니스 로직과 특정 도메인 문제 사이의 관계는 섹션을 통해 캡슐화되고 유지되므로 응용 프로그램 전체에 원래 산란 된 변경 사항을 잘 관리 할 수 있습니다. AOP의 관점에서 응용 프로그램은 단면 문제 및 비즈니스 로직 코드로 나눌 수 있습니다. 실제 개발에서 이러한 단면적 문제는 종종 비즈니스 로직 코드에 직접 포함됩니다. 얼굴 지향적 프로그래밍은 비즈니스 논리에서 단면 문제를 분리하는 문제를 해결하는 것입니다.
구현 방법 :
Spring은 기본적으로 JDK Dynamic Proxy를 AOP의 프록시로 사용합니다. 결함은 대상 클래스가 인터페이스를 구현해야한다는 것입니다. 그렇지 않으면 JDK 동적 프록시를 사용할 수 없습니다. 클래스가 인터페이스가 아닌 클래스 인 경우 Spring은 기본적으로 CGLIB 프록시를 사용합니다. JDK 동적 프록시는 Java의 반사 메커니즘을 통해 구현되며, 대상 클래스는 인터페이스를 구현해야하고 CGLIB는 클래스의 프록시를 구현해야합니다. 그 원칙은 지정된 대상 클래스에 대한 서브 클래스를 동적으로 생성하고 메소드 구현 향상을 무시하는 것이지만, 상속이 사용되기 때문에 최종 수정 된 클래스를 파악할 수 없습니다.
JDK 동적 프록시
JDK Dynamic Proxy는 프로그램 작동 중 대상 클래스에서 구현 한 인터페이스를 기반으로 프록시 클래스의 클래스 파일을 동적으로 생성합니다. 사용에는 주로 두 가지 클래스가 포함됩니다.
InvocationHandler 인터페이스 : 구현자가 해당 프록시 로직 구현을 제공 할 수있는 invoke(Object obj,Method method, Object[] args) 메소드를 제공합니다. 실제 구현에서 일부 특수 처리를 수행 할 수 있으며 매개 변수는 다음과 같습니다.
Object OBJ : 대상 클래스는 근접한 클래스입니다
방법 방법 : 실행 해야하는 대상 클래스의 메소드
Object [] args : 대상 방법의 매개 변수
프록시 클래스 : 동적 프록시 클래스를 얻기 위해 메소드 newProxyInstance (ClassLoader loader, Class[] interfaces, InvocationHandler h) 제공합니다.
샘플 코드 :
public interface Orderservice {public void createOrder (); } public class Orderserviceimpl은 Orderservice {@override public void createOrder () {System.out.println ( "주문 만들기"); }} public class OrderLogger {public void beforecreateorder () {system.out.println ( "순서를 작성하기 전에"); } public void aftercreateorder () {system.out.println ( "순서를 작성한 후"); }} package com.sl.aop; import java.lang.reflect.invocationHandler; import java.lang.reflect.method; import java.lang.reflect.proxy; public class serviceproxy empoction and invocationHandler {private 객체 대상 클래스; 개인 OrderLogger OrderLogger; Public ServiceProxy (Object TargetClass, OrderLogger OrderLogger) {this.targetClass = TargetClass; this.orderLogger = OrderLogger; } // 프록시 공개 개체 get getDynamicProxy () {return proxy.newProxyInstance (targetclass.getClass (). getClassLoader (), //이 클래스 로더 targetclass.getClass ()를 통해 프록시 객체를 만듭니다. // 동적 프록시 호출 메소드는 관련 invoctionHandler이며 최종적 으로이 invocationHandler의 호출 메소드를 통해 실제 메소드를 실행합니다. 객체 결과 = method.invoke (targetclass, args); this.orderLogger.afTerCreateOrder (); 반환 결과; }}테스트 클래스 :
패키지 com.sl.aop; import org.junit.test; public class aoptest {@test public void testdynamicproxy () {Orderserviceimpl servicempl = new OrderserviceImpl (); OrderLogger Logger = New OrderLogger (); Orderservice service = (Orderservice) New ServiceProxy (ServiceImpl, Logger) .getDynamicProxy (); service.createorder (); }}실행 결과 :
나는이 시점에 도달 할 때 실제로 약간 혼란스러워합니다. Proxy.newProxyInstance() 무엇을 반환합니까? 호출 방법은 어디에서 호출됩니까? JDK 소스 코드를 살펴 보겠습니다. DK Dynamic Proxy의 프로세스가 어떻게 보이는지 보겠습니다.
Call Proxy.newProxyInstance()->Proxy.getProxyClass0()->WeakCache.get() 소스 코드의 함수에 따라 먼저 찾으십시오.
약점 .class :
public v get (k key, p parameter) {objects.requirenonnull (매개 변수); expungestaleentries (); Object Cachekey = Cachekey.Valueof (키, 리 파티); // 특정 CACHEKEY CONCURRENTMAP에 대한 두 번째 레벨 valueMap을 게으르게 설치합니다. if (valueMap == null) {conscurrentMap <개체, 공급 업체 <V >> oldValuesMap = map.putifAbsent (cachekey, valueMap = new ConcurrenThashMap <> ()); if (OldValuesMap! = null) {valueMap = OldValuesMap; }} // valueMap 객체에서 // subkey에 저장된 가능한 공급 업체를 검색하고 가능한 공급 업체를 검색합니다. SubKey = Objects.RequirenOnnull (subKeyFactory.Apply (키, 매개 변수)); 공급 업체 <v> 공급 업체 = valueMap.get (subkey); 공장 공장 = null; while (true) {if (supplier! = null) {// 공급 업체는 공장이거나 cachevalue <v> 인스턴스 v value = supplier.get () 일 수 있습니다. if (value! = null) {return value; }} // Cache의 공급 업체는 // 또는 NULL을 반환 한 공급 업체가 없습니다 (CACHEVALUE // CACHEVALUE를 설치하는 데 성공하지 못한 공장) // 공장을 게으르게 구성하면 (Factory == NULL) {factory = New Factory (키, 매개 변수, 하위 키, 값 맵); } if (supplier == null) {supplier = valueMap.putifAbsent (subkey, factory); if (supplier == null) {// 성공적으로 공장 공급 업체 = 공장; } // 다른 공급 업체와 함께 재 시도} else {if (valueMap.replace (Subkey, Supplier, Factory)) {// 성공적으로 교체 // 공장 공급 업체와 함께 CACHEENTRY / ENCCESSFEN FACSORY // CHERNED CHERFED CLEARNED FACSORY = FACTORY; } else {// 현재 공급 업체 공급 업체 공급 업체를 다시 시도합니다. }}}} 함수 리턴 값을 볼 수 있습니다. 및 V value = supplier.get(); 계속해서 읽고 저녁 식사 = 공장이 실제로 공장 대상이라는 것을 알게되므로 Factory.get() 메서드를 계속보십시오.
public synchronized v get () {// 액세스 시리얼 화 // 공급 업체 <v> 공급 업체 = valuemap.get (subkey); if (supplier! = this) {// 우리가 기다리는 동안 변경된 무언가가 변경되었습니다. // 실패로 인해 cachevalue로 대체되었거나 실패로 인해 제거되었을 수도 있습니다 -> // roop retry null을 다시 반환하기 위해 null을 신호로 반환합니다. } // 여전히 미국 (공급자 == this) // 새 값을 만듭니다 v value = null; try {value = objects.requirenonnull (valueFactory.Apply (키, 매개 변수)); } 마침내 {if (value == null) {// 실패 값 map.remove에서 우리를 제거합니다 (subkey, this); }} // 여기에 도달 할 수있는 유일한 경로는 널 값이 아닌 값 Assert value! = null입니다. // cachevalue (약점) cachevalue <v> cachevalue = new cachevalue <> (value)로 랩 값을 랩합니다. // 우리를 cachevalue로 바꾸십시오 (이것은 항상 성공해야합니다) if (valuesMap.replace (subkey, this, cachevalue)) {// reversemap reversemap.put (cachevalue, boolean.true)에 넣습니다. } else {새 assertionError를 던지십시오 ( "여기에 도달해서는 안됩니다"); } // 우리를 새로운 cachevalue로 성공적으로 바꾸었다 -> 값을 반환 // return value; } 반환 값; 그런 다음 할당 문 value = Objects.requireNonNull(valueFactory.apply(key, parameter)); 직접 봅니다.
도대체는 무엇입니까?
public weepcache (bifunction <k, p,?> subkeyfactory, bifunction <k, p, v> valueFactory) {this.subkeyFactory = Objects.Requirenonnull (subkeyFactory); this.ValueFactory = Objects.Requirenonnull (ValueFactory); } private static final weakCache <classloader, class <?> [], class <? >> proxyClassCache = new 약점 <> (새로운 keyfactory (), new proxyClassFactory ()); valueFactory는 proxyclassfactory 유형 객체라는 것을 알 수 있으며 ProxyClassFactory. Apply()
공개 클래스 <?> 적용 (클래스 로더 로더, 클래스 <?> [] 인터페이스) {map <class <?>, boolean> 인터페이스 세트 = new IdentityHashMap <> (interfaces.length); for (class <?> intf : interfaces) { / * * 클래스 로더 가이 * 인터페이스의 이름을 동일한 클래스 객체로 해결하는지 확인하십시오. */ class <?> interfaceclass = null; {interfaceclass = class.forname (intf.getName (), False, Loader); } catch (classNotFoundException e) {} if (interfaceclass! = intf) {throw new 불법 행위 exception (intf + "는 클래스 로더에서 보이지 않습니다."); } / * * 클래스 객체가 실제로 * 인터페이스를 나타내는지 확인하십시오. */ if (! interfaceclass.isinterface ()) {새 불법 불법 행위 (interfaceclass.getName () + "interface가 아닙니다"); } / * *이 인터페이스가 복제본이 아닌지 확인하십시오. */ if (interfaceset.put (interfaceclass, boolean.true)! = null) {새 불법 행위 exception ( "반복 인터페이스 :" + interfaceclass.getName ()); }} 문자열 proxypkg = null; // int accessflags = modifier.public에서 프록시 클래스를 정의하는 패키지. 수정 자. / * * 비공개 프록시 인터페이스의 패키지를 기록하여 * 프록시 클래스가 동일한 패키지로 정의되도록합니다. * 모든 비 공개 프록시 인터페이스가 동일한 패키지에 있는지 확인하십시오. */ for (class <?> intf : interfaces) {int flags = intf.getModifiers (); if (! modifier.ispublic (flags)) {accessflags = modifier.final; 문자열 이름 = intf.getName (); int n = name.lastindexof ( '.'); 문자열 pkg = ((n == -1)? "": name.substring (0, n + 1)); if (proxypkg == null) {proxypkg = pkg; } else if (! pkg.equals (proxypkg)) {새로운 불법 불법 행위 ( "다른 패키지의 비 공개 인터페이스"); }}}} if (proxypkg == null) {// 비공개 프록시 인터페이스가없는 경우 com.sun.proxy 패키지 proxypkg = reflicutil.proxy_package + "를 사용하십시오."; } / * * 생성 할 프록시 클래스의 이름을 선택합니다. */ long num = nextUniqueNumber.getAndIncrement (); 문자열 proxyname = proxypkg + proxyclassnameprefix + num; / * * 지정된 프록시 클래스를 생성합니다. */ byte [] proxyclassfile = proxygenerator.generate proxyclass (proxyname, 인터페이스, AccessFlags); {return defineClass0 (로더, proxyname, proxyclassfile, 0, proxyclassfile.length); } catch (classformaterror e) { / * * 여기서 classformaterror는 ( * 프록시 클래스 생성 코드의 버그를 제외하고) 프록시 * 클래스 생성에 제공되는 인수의 다른 * 잘못된 측면이 있음을 의미합니다 (예 : 가상 기계 제한 * 초과). */ New ImpalargumentException을 던지십시오 (e.toString ()); }}}핵심 사항을 직접 그려냅니다.
바이트 [] proxyClassFile = proxygenerator.generateproxyclass (proxyname, 인터페이스, 액세스 플래그); return defineclass0 (로더, proxyname, proxyclassfile, 0, proxyclassfile.length);
ProxyGenerator.generateProxyClass 호출하면 마침내 프록시 클래스가 동적으로 생성되지만 어디에도 호출이라고 불리는 것으로 보입니다. 기사 csdn : //www.vevb.com/article/118935.htm 기사를 참조하고 동적으로 생성 된 이진 바이트 코드를 로컬로 출력하고 디 컴파일하여 그것을 확인하십시오. 테스트 코드는 다음과 같습니다.
public class aoptest {@test public void testdynamicproxy () {Orderserviceimpl servicempl = new OrderserviceImpl (); OrderLogger Logger = New OrderLogger (); Orderservice service = (Orderservice) New ServiceProxy (ServiceImpl, Logger) .getDynamicProxy (); service.createorder (); // 출력 동적 프록시 클래스 바이트 코드 CreateProxyClassFile (); } private static void createProxyClassFile () {문자열 이름 = "proxyObject"; 바이트 [] data = proxygenerator.generateproxyclass (이름, 새 클래스 [] {orderService.class}); fileoutputStream out = null; try {out = new FileOutputStream (name+". class"); System.out.println ((새 파일 ( "hello")). getAbsolutepath ()); out.write (데이터); } catch (filenotfoundException e) {e.printstacktrace (); } catch (ioexception e) {e.printstacktrace (); } 마침내 {if (null! = out) try {out.close (); } catch (ioexception e) {e.printstacktrace (); }}}}}}Java Decompiler 도구를 사용 하여이 바이너리 클래스 파일을 디 컴파일하십시오.
특정 동적 프록시 클래스 proxyObject.java :
import com.sl.aop.orderService; import java.lang.reflect.invocationhandler; import java.lang.reflect.method; import java.lang.reflect.proxy; import java.lang.reflect.undeclaredThrowableException; 공개 최종 클래스 확장 Pritice empless emplesser emplesser emplesser emplesser em prox empless em prox empless. 개인 정적 방법 M2; 개인 정적 방법 M3; 개인 정적 방법 M0; public proxyObject (invocationHandler paraminVocationHandler) {super (paraminVocationHandler); } public final boolean equals (object paramobject) {try {return ((boolean)) this.h.invoke (this, m1, new Object [] {paramobject})). booleanValue (); } catch (오류 | runtimeexception localError) {localError를 던지십시오; } catch (Throwable LocalThrowable) {새로운 미등성이없는 출시 (LocalThrowable); }} public final String toString () {try {return (string) this.h.invoke (this, m2, null); } catch (오류 | runtimeexception localError) {localError를 던지십시오; } catch (Throwable LocalThrowable) {새로운 미등성이없는 출시 (LocalThrowable); }} public final void createOrder () {try {this.h.invoke (this, m3, null); 반품; } catch (오류 | runtimeexception localError) {localError를 던지십시오; } catch (Throwable LocalThrowable) {새로운 미등성이없는 출시 (LocalThrowable); }} public final int hashcode () {try {return (returg) this.h.invoke (this, m0, null)). intvalue (); } catch (오류 | runtimeexception localError) {localError를 던지십시오; } catch (Throwable LocalThrowable) {새로운 미등성이없는 출시 (LocalThrowable); }} static {try {m1 = class.forname ( "java.lang.object"). getMethod ( "equals", new class [] {class.forname ( "java.lang.object")); m2 = class.forname ( "java.lang.object"). getMethod ( "Tostring", New Class [0]); m3 = class.forname ( "com.sl.aop.orderservice"). getMethod ( "CreateOrder", New Class [0]); m0 = class.forname ( "java.lang.object"). getMethod ( "Hashcode", New Class [0]); 반품; } catch (nosuchmethodexception localNosuchMethodexception) {새로운 nosuchmethoderror (localnosuchmethodexception.getMessage ()); } catch (classNotFoundException LocalClassNotFoundException) {새 noclassDeffoundError (localClassNotFoundException.getMessage ()); }}마지막으로 Invoke에 대한 부분을 보았습니다.
public final void createOrder () {try {this.h.invoke (this, m3, null); 반품; } catch (오류 | runtimeexception localError) {localError를 던지십시오; } catch (Throwable LocalThrowable) {새로운 미등성이없는 출시 (LocalThrowable); }}실제로, 동적 프록시 클래스는 프록시에서 상속되고 대상 클래스에 의해 상속 된 인터페이스를 구현합니다. 호출 방법은 CreateOrder 메소드에서 호출되며, 이는 단면 논리의 이식을 구현합니다. 여기서 우리는 또한 프록시 클래스가 실제로 클래스가 아닌 인터페이스 프록시를 목표로하기 때문에 JDK 동적 프록시의 대상 클래스가 인터페이스를 구현 해야하는 이유도 있습니다. 동적 프록시 클래스는 프록시에서 자체적으로 상속되며 Java는 여러 상속을 허용하지 않습니다. 동적 프록시 클래스와 대상 클래스는 실제로 인터페이스를 각각 구현합니다. 프록시 클래스는 InvocationHandler.invoke를 통해 대상 클래스 메소드에 대한 호출을 실현합니다.
CGLIB 동적 프록시
CGLIB 프록시는 바이트 코드 프로세싱 프레임 워크 ASM을 사용하여 바이트 코드를 변환하고 새로운 클래스를 생성하고 서브 클래스의 메소드 차단 기술을 사용하여 모든 상위 클래스 방법을 가로 채서 크로스 컷팅 로직을 구현하여 반사 기술을 사용하는 JDK 동적 프록시보다 효율적입니다. 그러나 CGLIB의 원리는 대상 클래스에 대한 서브 클래스 프록시 클래스를 동적으로 생성하는 것이므로 최종으로 선언 된 메소드에 대해서는 근접 할 수 없습니다. 그것의 사용은 주로 두 가지 범주를 포함합니다.
MethodInterceptor 인터페이스 :이 인터페이스는 주로 대상 클래스 메소드의 호출을 가로 채기 위해 사용되는 메소드 intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) 제공합니다.
객체 Arg0, : 프록시 된 대상 클래스
방법 arg1, 대표 방법
Object [] arg2, 메소드 매개 변수
MethodProxy arg3 : 프록시 방법의 메소드 프록시 객체
Enhancer 클래스 : 프록시 클래스를 만드는 데 사용됩니다
예:
MethodInterceptor 인터페이스를 구현하십시오. 프록시 클래스가 메소드를 호출하면 cglib는 Methodinterceptor Interface 인터셉트 메소드를 다시 호출하여 표면 로직을 직조합니다.
패키지 com.sl.aop; import java.lang.reflect.method; import org.springframework.cglib.proxy.enhancer; import org.springframework.cglib.proxy.methodinterceptor; import org.springframework.cglib.proxy.methodproxy; {개인 객체 targetclass; 개인 OrderLogger OrderLogger; public cglibserviceproxy (Object TargetClass, OrderLogger OrderLogger) {this.targetClass = TargetClass; this.orderLogger = OrderLogger; } / *** 프록시 개체 생성** / public 객체 getInstance () {enhancer enhancer = new enhancer (); // 대상 클래스를 설정 (프록시 해야하는 클래스) enhancer.setSuperClass (this.targetClass.getClass ()); // 콜백 메소드 Enhancer.setCallback (this); // 프록시 객체 작성 return enternance.create (); } / *** 모든 대상 클래스 메소드를 가로 채십시오* / @ @override public object intercept (Object Arg0, Method Arg1, Object [] arg2, MethodProxy Arg3) 던지기 가능 {OrderLogger.beforecreateorder (); Object O1 = arg3.invokesuper (arg0, arg2); OrderLogger.AfTerCreateOrder (); 반환 O1; }}테스트 방법 :
public void testdynamicproxy () {System.setProperty (debuggingclasswriter.debug_location_property, "d : // class"); Orderserviceimpl servicempl = new Orderserviceimpl (); OrderLogger Logger = New OrderLogger (); cglibserviceproxy proxy = 새로운 cglibserviceproxy (ServiceImpl, Logger); // 서브 클래스를 생성하여 프록시 클래스를 만듭니다. proxyimp.createorder (); }결과:
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D://class"); CGLIB Dynamic Proxy 클래스를 지정된 디렉토리로 출력하고 프록시 클래스의 실제 얼굴을 디 컴파일하고 확인하십시오.
패키지 com.sl.aop; import com.sl.aop.orderServiceimpl; import java.lang.reflect.method; import org.springframework.cglib.core.reflectutils; import org.springframework.cgleib.core.signature; import org.springfrflib.cglib.callback; org.springframework.cglib.proxy.factory; import org.springframework.cglib.proxy.methodinterceptor; import org.springframework.cglib.proxy.methodproxy; public class Orderserviceimpl $$ EnhancerBycglib $$ 1779a4 Extends Orderveric or Order -veren ordervice implet impless empless findermpl indermpl bower intrements (public class org.spramframework.cglib.proxy.methodproxy; cglib $ bound; 공개 정적 객체 cglib $ factory_data; 개인 정적 최종 STHREADLOCAL CGLIB $ THREAD_CALLBACKS; 개인 정적 최종 콜백 [] cglib $ static_callbacks; 개인 메소드 인터셉터 cglib $ callback_0; 비공개 정적 객체 cglib $ callback_filter; 개인 정적 최종 방법 CGLIB $ CreateOrder $ 0 $ 방법; 개인 정적 최종 방법 프록시 CGLIB $ CreateOrder $ 0 $ proxy; 개인 정적 최종 개체 [] cglib $ emplyArgs; 개인 정적 최종 방법 CGLIB $는 $ 1 $ 방법과 같습니다. 개인 정적 최종 방법 Proxy Cglib $는 $ 1 $ proxy; 개인 정적 최종 방법 CGLIB $ TOSTRING $ 2 $ 방법; 개인 정적 최종 방법 프록시 CGLIB $ TOSTRING $ 2 $ proxy; 개인 정적 최종 방법 CGLIB $ HASHCODE $ 3 $ 방법; 개인 정적 최종 방법 프록시 CGLIB $ 해시 코드 $ 3 $ 프록시; 개인 정적 최종 메소드 CLONE $ 4 $ 방법; 개인 정적 최종 방법 프록시 CGLIB $ 클론 $ 4 $ 프록시; 정적 void cglib $ statichook1 () {cglib $ thread_callbacks = new ThreadLocal (); cglib $ emplyargs = 새 개체 [0]; class var0 = class.forname ( "com.sl.aop.orderServiceimpl $$ EnhancerByCglib $$ 17779aa4"); 클래스 var1; 메소드 [] var10000 = reclicutils.findmethods (new String [] { "equals", "(ljava/lang/object;) z", "tostring", "() ljava/lang/string;", "해시 코드", "() i", "clone", "() ljava/lang/object; class.forname ( "java.lang.object"). getDeclaredMethods ()); cglib $는 $ 1 $ method = var10000 [0]; cglib $는 $ 1 $ proxy = methodproxy.create (var1, var0, "(ljava/lang/object;) z", "equals", "cglib $ $ 1"); cglib $ tostring $ 2 $ method = var10000 [1]; cglib $ toString $ 2 $ proxy = methodProxy.create (var1, var0, "() ljava/lang/string;", "tostring", "cglib $ toString $ 2"); cglib $ 해시 코드 $ 3 $ method = var10000 [2]; CGLIB $ HASHCODE $ 3 $ proxy = MethodProxy.create (Var1, var0, "() i", "Hashcode", "cglib $ hashcode $ 3"); cglib $ 클론 $ 4 $ method = var10000 [3]; cglib $ 복제 $ 4 $ proxy = MethodProxy.create (var1, var0, "() ljava/lang/object;", "clone", "cglib $ clone $ 4"); cglib $ createOrder $ 0 $ method = recintUtils.findMethods (new String [] { "createOrder", "() v"}, (var1 = class.forname ( "com.sl.aop.orderserviceimpl"). getDeclaredMethods ()) [0]; cglib $ createorder $ 0 $ proxy = MethodProxy.create (var1, var0, "() v", "createorder", "cglib $ createOrder $ 0"); } 최종 void cglib $ createorder $ 0 () {super.createorder (); } public final void createOrder () {MethodInterceptor var10000 = this.cglib $ callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ callback_0; } if (var10000! = null) {var10000.intercept (this, cglib $ createOrder $ 0 $ method, cglib $ emptyArgs, cglib $ 0 $ proxy); } else {super.createorder (); }} Final Boolean Cglib $는 $ 1 (Object Var1) {return super.equals (var1); } public final boolean equals (Object Var1) {MethodInterceptor var10000 = this.cglib $ callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ callback_0; } if (var10000! = null) {Object var2 = var10000.intercept (this, cglib $는 $ 1 $ method, new Object [] {var1}, cglib $ $ 1 $ proxy); return var2 == null? false : ((boolean) var2) .booleanValue (); } else {return super.equals (var1); }} 최종 문자열 cglib $ toString $ 2 () {return super.toString (); } public final String toString () {MethodInterceptor var10000 = this.cglib $ callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ callback_0; } return var10000! = null? (string) var10000.intercept (this, cglib $ toString $ 2 $ method, cglib $ tomargs, cglib $ toString $ 2 $ proxy) : super.toString (); } 최종 int cglib $ hashcode $ 3 () {return super.hashcode (); } public final int hashcode () {methodinterceptor var10000 = this.cglib $ callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ callback_0; } if (var10000! = null) {Object var1 = var10000.intercept (this, cglib $ hashcode $ 3 $ method, cglib $ emplyArgs, cglib $ hashcode $ 3 $ proxy); return var1 == null? 0 : ((number) var1) .intValue (); } else {return super.hashcode (); }} 최종 객체 cglib $ 클론 $ 4 ()는 clonenotsupportedException {return super.clone (); } 보호 된 최종 오브젝트 클론 ()은 클로네 노트 업 포트 프리드 렉스크를 던지 었습니다. {MethodInterceptor var10000 = this.cglib $ callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ callback_0; } return var10000! = null? var10000.intercept (this, cglib $ clone $ 4 $ method, cglib $ emptyArgs, cglib $ 복제 $ 4 $ proxy) : super.clone (); } public static methodproxy cglib $ findmethodproxy (signature var0) {String var10000 = var0.toString (); switch (var10000.hashcode ()) {case -2138148221 : if (var10000.equals ( "createorder () v")) {return cglib $ $ 0 $ proxy; } 부서지다; 사례 -508378822 : if (var10000.equals ( "clone () ljava/lang/object;")) {return cglib $ clone $ 4 $ proxy; } 부서지다; 사례 1826985398 : if (var10000.equals ( "equals (ljava/lang/object;) z") {return cglib $ $ 1 $ proxy; } 부서지다; 사례 1913648695 : if (var10000.equals ( "tostring () ljava/lang/string;")) {return cglib $ toString $ 2 $ proxy; } 부서지다; 사례 1984935277 : if (var10000.equals ( "hashcode () i")) {return cglib $ hashcode $ 3 $ proxy; }} return null; } public OrderserViceimpl $$ EnhancerBycglib $$ 17779aa4 () {cglib $ bind_callbacks (this); } public static void cglib $ set_thread_callbacks (callback [] var0) {cglib $ thread_callbacks.set (var0); } public static void cglib $ set_static_callbacks (콜백 [] var0) {cglib $ static_callbacks = var0; } private static final void cglib $ bind_callbacks (Object var0) {Orderserviceimpl $$ EnhancerByCglib $$ 17779aa4 var1 = (Orderserviceimpl $$ EnhancerByCglib $$ 17779aa4) var0; if (! var1.cglib $ bound) {var1.cglib $ bound = true; Object var10000 = cglib $ thread_callbacks.get (); if (var10000 == null) {var10000 = cglib $ static_callbacks; if (cglib $ static_callbacks == null) {return; }} var1.cglib $ Callback_0 = (MethodInterceptor) ((Callback []) var10000) [0]; }} public Object NewInstance (Callback [] var1) {cglib $ set_thread_callbacks (var1); Orderserviceimpl $$ EnhancerBycglib $$ 17779aa4 var10000 = new Orderserviceimpl $$ EnhancerBycglib $$ 17779aa4 (); cglib $ set_thread_callbacks ((Callback []) null); 반환 var10000; } public Object NewInstance (Callback var1) {cglib $ set_thread_callbacks (new Callback [] {var1}); Orderserviceimpl $$ EnhancerBycglib $$ 17779aa4 var10000 = new Orderserviceimpl $$ EnhancerBycglib $$ 17779aa4 (); cglib $ set_thread_callbacks ((Callback []) null); 반환 var10000; } public Object NewInstance (class [] var1, object [] var2, callback [] var3) {cglib $ set_thread_callbacks (var3); Orderserviceimpl $$ EnhancerBycglib $$ 17779aa4 var10000 = new Orderserviceimpl $$ EnhancerBycglib $$ 17779aa4; 스위치 (var1.length) {case 0 : var10000. <init> (); cglib $ set_thread_callbacks ((Callback []) null); 반환 var10000; 기본값 : New New OregalArgumentException ( "생성자 찾을 수 없음")을 던지십시오. }} public Callback getCallback (int var1) {cglib $ bind_callbacks (this); MethodInterceptor var10000; 스위치 (var1) {case 0 : var10000 = this.cglib $ callback_0; 부서지다; 기본값 : var10000 = null; } return var10000; } public void setCallback (int var1, 콜백 var2) {switch (var1) {case 0 : this.cglib $ callback_0 = (MethodInterceptor) var2; 기본값 :}} public Callback [] getCallbacks () {cglib $ bind_callbacks (this); 새 콜백을 반환합니다 [] {this.cglib $ callback_0}; } public void setCallbacks (Callback [] var1) {this.cglib $ callback_0 = (MethodInterceptor) var1 [0]; } static {cglib $ statichook1 (); }}위의 코드에서 프록시 클래스 OrderserViceimpl $$ EnhancerByCglib $$ 17779AA4는 대상 클래스 OrderserViceImpl을 상속하고 인터페이스 공장을 구현한다는 것을 알 수 있습니다. 프록시 클래스에서 두 가지 방법 cglib $ createorder $ 0 및 createorder가 생성됩니다.
cglib $ createorder $ 0 메소드는 대상 클래스의 supper.createOrder 직접 호출합니다
CreateOrder 메소드는 먼저 MethodInterceptor 인터페이스의 콜백이 구현되었는지 여부를 계산합니다. 존재하는 경우 MethodInterceptor 인터페이스 인터셉트 메소드가 호출됩니다. 이전 구현에 따르면 대상 방법에 대한 호출이 구현됩니다. Object o1 = arg3.invokeSuper(arg0, arg2) 가 구현됩니다. 호출기는 실제로 직접 호출되는 프록시 클래스의 CGLIB$createOrder$0() 메소드이며 대상 클래스 CreateOrder가 마침내 호출됩니다.
두 에이전트의 비교
JDK 동적 프록시 :
프록시 클래스와 대의원 클래스는 동일한 인터페이스를 구현합니다. 주로 프록시 클래스를 통해 InvocationHandler를 구현하고 INVOKE 메소드를 다시 작성하여 동적 프록시를 수행합니다. 이 방법은 호출 방법에서 향상됩니다. 방법의 장점 : 하드 코딩 된 인터페이스가 필요하지 않으며 코드 재사용 속도가 높습니다. 단점 : 인터페이스에서 구현할 수있는 대의원 클래스 만
CGLIB 동적 프록시 :
프록시 클래스는 대의원 클래스를 부모 클래스로 받아들이고 비 결국 대의원 메소드에 대한 두 가지 방법을 만듭니다. 하나는 대의원 메소드 서명과 동일한 메소드이며,이 메소드에서 슈퍼를 통해 대의원 메소드를 호출합니다. 다른 하나는 프록시 클래스에 고유 한 방법입니다. 프록시 방법에서는 MethodInterceptor 인터페이스를 구현하는 객체가 있는지 여부가 결정됩니다. 그것이 존재하면, 인터셉트 메소드는 대의원 방법을 프록시하도록 호출됩니다. 장점 : 런타임에서 클래스 또는 인터페이스의 작동을 향상시킬 수 있으며 대의원 클래스는 인터페이스를 구현할 필요가 없습니다. 단점 : 최종 클래스와 최종 방법을 프록시 할 수는 없습니다.
요약
위는이 기사의 전체 내용입니다. 이 기사의 내용에 모든 사람의 연구 나 작업에 대한 특정 참조 가치가 있기를 바랍니다. 궁금한 점이 있으면 의사 소통을 위해 메시지를 남길 수 있습니다. Wulin.com을 지원 해주셔서 감사합니다.