1. 프록시 모드의 정의
프록시 객체가있는 객체를 제공하고 프록시 객체는 원래 객체에 대한 액세스를 제어합니다.
유명한 프록시 패턴의 예는 참조 계산입니다. 복잡한 객체의 여러 사본이 필요할 때 프록시 패턴을 메타 모드와 결합하여 메모리의 양을 줄일 수 있습니다. 일반적인 접근 방식은 원래 객체를 참조하는 복잡한 객체와 다중 프록시를 만드는 것입니다. 에이전트에서 작용하는 작업은 원래 객체로 전달됩니다. 모든 에이전트가 존재하지 않으면 복잡한 물체가 제거됩니다.
프록시 모델을 이해하는 것은 간단하지만 실제로 인생에는 프록시 모델이 있습니다.
기차역에서 기차 티켓을 구입할 수 있지만 기차 티켓 영업 사무소에서도 구입할 수도 있습니다. 여기의 열차 티켓 영업 사무소는 기차역에서 티켓 구매 대리인입니다. 즉, 우리는 판매 아울렛에서 티켓 구매 요청을 발행합니다. 판매 아울렛은 요청을 기차역으로 보내고 기차역은 구매에 대한 성공적인 응답을 판매점에 보낼 것입니다. 그리고 판매 아울렛이 다시 알려줍니다.
그러나 티켓은 판매 아울렛에서만 구입할 수 있지만 환불 할 수는 없지만 기차역에서 티켓을 구입할 수 있으므로 대리인이 지원하는 운영은 의뢰 된 오브젝트의 운영과 다를 수 있습니다.
프로그램을 작성할 때 발생할 또 다른 예를 드리겠습니다.
int compute (string exp1)를 호출하여 접미사 표현식의 계산을 구현할 수있는 기존 프로젝트 (소스 코드 만 호출 할 수 있음)가있는 경우. 이 프로젝트를 사용하여 Infix 표현식의 계산을 구현하려면 프록시 클래스를 작성하고 컴퓨팅 (String Exp2)을 정의 할 수 있습니다. 이 exp2 매개 변수는 디픽스 표현식입니다. 따라서 기존 프로젝트의 compute ()를 호출하기 전에 접미어 표현식 (preprocess)으로 디스 픽스 표현식을 변환 한 다음 기존 프로젝트의 compute ()를 호출해야합니다. 물론 반환 값을 받고 파일 저장 (후 프로세스)과 같은 다른 작업을 수행 할 수도 있습니다. 이 프로세스는 프록시 모드를 사용합니다.
컴퓨터를 사용하는 경우 프록시 모드 애플리케이션도 발생합니다.
원격 프록시 : 중국의 GFW로 인해 Facebook에 액세스 할 수 없습니다. 벽을 탐색하여 (프록시 설정) 액세스 할 수 있습니다. 액세스 프로세스는 다음과 같습니다.
(1) 사용자는 HTTP 요청을 프록시로 보냅니다.
(2) 프록시는 HTTP 요청을 웹 서버로 보냅니다.
(3) 웹 서버는 HTTP 응답을 프록시에 보냅니다.
(4) 프록시는 HTTP 응답을 사용자에게 다시 보냅니다.
2. 정적 프록시
소위 정적 프록시는 편집 단계에서 프록시 클래스가 생성되어 프록시 오브젝트에서 일련의 작업을 완료 함을 의미합니다. 다음은 프록시 패턴의 구조 클래스 다이어그램입니다.
1. 프록시 모델의 참가자
프록시 모드에는 네 가지 역할이 있습니다.
주제 인터페이스 : 즉, 프록시 클래스에서 구현 한 동작 인터페이스입니다.
대상 객체 : 즉, 대상이 프록시되는 것입니다.
프록시 객체 : 실제 주제 클래스를 캡슐화하는 데 사용되는 프록시 클라이언트는 다음은 프록시 패턴의 클래스 다이어그램 구조입니다.
2. 에이전트 모델 구현 아이디어
프록시 객체와 대상 객체는 동일한 동작 인터페이스를 구현합니다.
프록시 클래스와 대상 클래스는 인터페이스 로직을 별도로 구현합니다.
프록시 클래스의 생성자에 대상 객체를 인스턴스화하십시오.
프록시 클래스에서 대상 객체의 동작 인터페이스를 호출합니다.
클라이언트가 대상 객체의 동작 인터페이스를 호출하려는 경우 프록시 클래스를 통해서만 작동 할 수 있습니다.
3. 정적 프록시의 예
다음은 정적 프록시를 설명하기위한 게으른 하중 예입니다. 서비스 시스템을 시작하면 특정 클래스를로드하는 데 시간이 오래 걸릴 수 있습니다. 더 나은 성능을 얻기 위해 시스템을 시작할 때 종종이 복잡한 클래스를 초기화하지 않고 대신 프록시 클래스를 초기화합니다. 이렇게하면 분리를 위해 프록시를 사용하여 리소스 소비 방법을 분리하여 시스템 시작 속도 속도를 높이고 사용자의 대기 시간을 줄일 수 있습니다.
주제 인터페이스를 정의합니다
공개 인터페이스 주제 {public void sayhello (); public void saygoodbye ();} 대상 클래스를 정의하고 주제 인터페이스를 구현하십시오
공개 클래스 realsubject 구현 주제 {public void sayhello () {System.out.println ( "Hello World"); } public void saygoodBye () {System.out.println ( "Goodbye World"); }} 대상 객체를 프록시하기 위해 프록시 클래스를 정의하십시오.
공개 클래스 staticProxy는 주제 {private realsubject realsubject = null; public staticproxy () {} public void sayhello () {// 그 당시로드, 게으른로드 if (realSubject == null) {realSubject = new realSubject (); } realSubject.sayHello (); } // saygoodbye 방법이 동일합니다 ...} 클라이언트를 정의하십시오
public class client {public static void main (String [] args) {staticproxy sp = new staticProxy (); sp.sayhello (); sp.saygoodbye (); }}위는 정적 프록시의 간단한 테스트 예입니다. 실용적이지 않을 수도 있습니다. 그러나 이것은 사실이 아닙니다. 프록시를 사용하여 대상 객체 방법을 변환 할 수도 있습니다. 예를 들어, 데이터베이스 연결 풀에서 일련의 연결이 생성됩니다. 연결이 자주 열리도록하기 위해 이러한 연결은 거의 닫히지 않습니다. 그러나 우리는 항상 열린 연결을 닫는 습관이 있습니다. 이런 식으로 프록시 모드를 사용하여 연결 인터페이스의 닫기 메소드를 재 록시하고 실제로 연결#Close 메소드를 실행하는 대신 데이터베이스 연결 풀로 재활용하도록 변경할 수 있습니다. 다른 많은 예가 있으며 직접 경험해야합니다.
3. 동적 에이전트
동적 프록시는 런타임에서 동적으로 프록시 클래스를 생성하는 것을 의미합니다. 즉, 프록시 클래스의 바이트 코드는 런타임에 현재 프록시의 클래스 로더에 생성되어로드됩니다. 정적 처리 클래스와 비교할 때 동적 클래스에는 많은 이점이 있습니다.
실제 주제에 대해 완전히 동일한 캡슐화 클래스를 작성할 필요가 없습니다. 주제 인터페이스에 많은 메소드가있는 경우 각 인터페이스에 대한 프록시 메소드를 작성하는 것도 번거 롭습니다. 인터페이스가 변경되면 실제 테마 및 프록시 클래스를 수정해야하며 시스템 유지 보수에는 도움이되지 않습니다.
일부 동적 프록시 생성 방법을 사용하면 런타임시 프록시 클래스의 실행 논리를 공식화하여 시스템의 유연성을 크게 향상시킬 수 있습니다.
Dynamic Proxy를 생성하는 방법에는 여러 가지가 있습니다. JDK는 Dynamic Proxy, CGLIB, Javassist 등과 함께 제공됩니다. 이러한 방법에는 고유 한 장점과 단점이 있습니다. 이 기사는 주로 JDK에서 동적 프록시 및 소스 코드 분석의 사용을 탐구합니다.
다음은 JDK에서 동적 프록시 사용을 설명하는 예입니다.
공개 클래스 DynamicProxy는 invocationHandler {private realSubject = null; 공개 객체 호출 (개체 프록시, 메소드 메소드, Object [] args) {if (realSubject == null) {realSubject = new realSubject (); } method.invoke (realSubject, args); realsubject를 반환하십시오. }}클라이언트 코드 예제
public class client {public static void main (strings [] args) {subject subject = (주제) proxy.newinstance (classLoader.getSystemLoader (), realSubject.class.getInterfaces (), new DynamicProxy ()); 대상 .sayhello (); 대상 .saygoodbye (); }}위 코드에서 볼 수 있듯이 JDK에서 동적 프록시를 사용해야합니다. 정적 메소드 proxy.newinstance (ClassLoader, interfaces [], invokeHandler)를 사용하여 동적 프록시 클래스를 만듭니다. NewInstance 메소드에는 세 가지 매개 변수가 있으며,이 매개 변수는 클래스 로더, 프록시 클래스를 구현하려는 인터페이스 목록 및 InvokeHandler 인터페이스를 구현하는 인스턴스를 나타냅니다. 동적 프록시는 각 방법의 실행 프로세스를 처리를위한 호출 방법에 적용했습니다.
JDK Dynamic Proxy는 프록시가 인터페이스 여야하지만 간단한 클래스는 할 수 없습니다. JDK Dynamic Proxy가 생성 한 프록시 클래스는 프록시 클래스를 상속하고 프록시 클래스는 전달한 모든 인터페이스 목록을 구현합니다. 따라서 유형을 인터페이스 유형으로 캐스트 할 수 있습니다. 아래는 프록시의 구조 다이어그램입니다.
프록시는 모든 정적 메소드임을 알 수 있으므로 프록시 클래스가 인터페이스를 구현하지 않으면 프록시 유형이며 인스턴스 메소드가 없습니다.
물론, 가입하면 특정 인터페이스를 구현하지 않는 클래스를 프록시해야 하며이 클래스의 메소드는 다른 인터페이스로 정의 된 방법과 동일하며 반사를 사용하여 쉽게 구현할 수 있습니다.
Public Class DynamicProxy는 invokeHandler {// 프라이빗 대상 클래스 대상 클래스를 프록시하려는 클래스; //이 클래스 초기화 public DynamicProxy (TargetClass TargetClass) {this.targetClass = targetclass; } public Object Invoke (개체 프록시, 메소드 메소드, 오브젝트 [] args) {// 프록시하려는 클래스를 얻기 위해 반사를 사용하여 myMethod = targetclass.getClass (). getDeclaredMethod (method.getName (), method.getParameterTypes ()); myMethod.setAccessible (true); MyMethod.invoke (TargetClass, Args)를 반환합니다. }}4. JDK 동적 프록시 소스 코드 분석 (JDK7)
위의 예를 살펴본 후 동적 프록시를 사용하는 방법을 알고 있습니다. 그러나 프록시 클래스가 어떻게 생성되는지, 누가 호출 방법 등을 불렀는지에 대해 여전히 안개가 큽니다. 다음 분석
1. 프록시 객체는 어떻게 생성됩니까?
먼저 proxy.newinstance 메소드의 소스 코드를보십시오.
public static 객체 NewProxyInstance (클래스 로더 로더, 클래스 <?> [] 인터페이스, invocationHandler h)는 불법적 인 정보 {} // 인터페이스 정보 최종 클래스 받기 <?> [] intfs = interfaces.clone (); 최종 보안 관리자 sm = system.getSecurityManager (); if (sm! = null) {checkProxyAccess (reflection.getCallerClass (), 로더, intfs); } // 프록시 클래스 생성 클래스 <?> cl = getProxyClass0 (로더, intfs); // ... 좋아, 전반전을 봐}}소스 코드에서 프록시 클래스의 생성은 getProxyClass0 메소드에 의존한다는 것을 알 수 있습니다. 다음으로 GetProxyClass0 소스 코드를 살펴 보겠습니다.
private static class <?> getProxyClass0 (클래스 로더 로더, 클래스 <?> ... 인터페이스) {// 인터페이스 목록 수는 0xffff if (interfaces.length> 65535)를 초과 할 수 없습니다. } // 여기서 참고, 다음 설명은 proxyClassCache.get (로더, 인터페이스)를 반환하기 위해 자세히 제공됩니다. } proxyclasscache.get에 대한 설명은 다음과 같습니다. 인터페이스 목록을 구현하는 프록시 클래스가 이미 존재하는 경우 캐시에서 직접 가져갑니다. 존재하지 않으면 proxyclassfactory를 통해 생성됩니다.
proxyclasscache.get의 소스 코드를보기 전에 proxyClassCache를 간략하게 이해해 봅시다 :
개인 정적 최종 약점 <클래스 로더, 클래스 <?> [], 클래스 <? >> proxyClassCache = new 약점 <> (new keyFactory (), new proxyClassFactory ());
ProxyClassCache는 약한 캐시 유형 캐시입니다. 생성자에는 두 가지 매개 변수가 있습니다. 그중 하나는 프록시 클래스를 생성하는 데 사용되는 대중성입니다. 다음은 proxyclasscache.get의 소스 코드입니다.
최종 클래스 약한 카슈 <k, p, v> {... public v get (k 키, p 매개 변수) {}}여기서 k는 키를 나타내고, p는 매개 변수를 나타내고, v는 값을 나타냅니다.
public v get (k key, p parameter) {// java7 nullobject jec너지 메소드, 매개 변수가 비어 있으면 지정된 메시지의 예외가 발생합니다. 비어 있지 않으면 반환하십시오. Objects.Requirenonnull (매개 변수); // 약한 참조를 보유한 약한 해시 맵의 데이터 구조를 정리하며, 일반적으로 ExpungestalEentries ()를 캐시하는 데 사용됩니다. // 큐에서 CacheKey를 가져옵니다. 객체 CACHEKEY = CACHEKEY.VALUEOF (key, refqueue); // 게으른 하중으로 공급 업체를 채 웁니다. Concurrent는 스레드-안전 맵 ConcurrentMap <객체, 공급 업체 <v >> valueMap = map.get (cachekey)입니다. 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) {// 공급 업체에서 값을 얻습니다. 이 값은 공장 또는 캐시 실현 일 수 있습니다. // 다음 세 문장은 핵심 코드이며,이 코드는 invokeHandler를 구현하고 필요한 정보를 포함하는 클래스를 반환합니다. v value = supplier.get (); if (value! = null) {return value; }} // elose cache // 또는 반환 된 공급 업체는 NULL (CACHEVALUE // CACHEVALUE를 설치하는 데 성공하지 못한 공장)에 공급 업체가 없습니다. // 다음 과정은 (팩토리 == NULL) {// factory} if (supplier == NULL)} elour} elour}} if (inctory == null) {// factory}를 작성하는 과정입니다. While Loop의 기능은 InvokeHandler를 구현하는 클래스를 지속적으로 얻는 것입니다. 이 클래스는 캐시에서 얻거나 proxyfactoryclass에서 생성 될 수 있습니다.
공장은 공급 업체 <v> 인터페이스를 구현하는 내부 클래스입니다. 이 클래스는 get 메소드를 무시하고 유형 proxyfactoryclass의 인스턴스 메소드가 Get 메소드에서 호출됩니다. 이 방법은 프록시 클래스를 만드는 진정한 방법입니다. proxyFactoryClass#Apply Method의 소스 코드를 보자.
공개 클래스 <?> 적용 (클래스 로더 로더, 클래스 <?> [] 인터페이스) {map <class <?>, boolean> 인터페이스 세트 = new IdentityHashMap <> (interfaces.length); for (class <?> intf : interfaces) { /* 클래스 로더 가이 인터페이스의 이름을 동일한 클래스 객체로 해결하는지 확인하십시오.* / class <?> interfaceclass = null; {// 각 interfaceclass = class.forname (intf.getName (), False, Loader)에 대한 정보로드; } catch (classNotFoundException e) {} // 자신의 클래스로드로로드 된 클래스가 당신이 통과 한 클래스와 같지 않으면 (interfaceclass! = intf) 예외를 던지면 {new new OregalArgumentException (intf + "가 클래스 로더에서 보이지 않습니다); } // 수신이 인터페이스 유형이 아닌 경우 (! interfaceclass.isinterface ()) {throw new neveralargumentexception (interfaceclass.getName () + "interface가 아닙니다"); } // 인터페이스가 반복되는지 여부를 확인하십시오 (interfaceset.put (interfaceclass, boolean.true)! = null) {throw new new oforgumentException ( "반복 인터페이스 :" + interfaceclass.getname ()); }} 문자열 proxypkg = null; // 프록시 클래스를 동일한 패키지에 정의되도록 비공개 프록시 인터페이스의 패키지를 기록하는 프록시 클래스를 정의하는 패키지. * 모든 비 공개 프록시 인터페이스가 동일한 패키지에 있는지 확인하십시오. *//이 단락은 통과 한 인터페이스에 공개되지 않은 인터페이스가 있는지 여부에 따라 다릅니다. 그렇다면이 모든 인터페이스를 하나의 패키지로 정의해야합니다. 그렇지 않으면 (class <?> intf : interfaces) {int flags = intf.getModifiers (); if (! modifier.ispublic (flags)) {문자열 이름 = 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 (); // 임의의 프록시 클래스의 클래스 이름을 생성합니다. $ proxy + num 문자열 proxyname = proxypkg + proxyclassnameprefix + num; /** 프록시 클래스의 클래스 파일을 생성하고 바이트 스트림을 반환*/ byte [] proxyclassfile = proxygenerator.generateproxyclass (proxyname, interfaces); {return defineClass0 (로더, proxyname, proxyclassfile, 0, proxyclassfile.length); } catch (classformaterror e) {// end strash new 불법 행위 exception (e.toString ()); }}}위에서 언급 한 proxyfactoryclass#apply는 실제로 부정확 한 프록시 클래스를 생성하는 방법입니다. 여기서 소스 코드를 읽은 후에는 proxygenerator#generateproxyclass가 프록시 클래스를 진정으로 생성하는 방법임을 알게 될 것입니다. Java 클래스 바이트 코드 구성에 따라 해당 클래스 파일을 생성하십시오 (다른 기사 Java Bytecode Learning Notes 참조). proxygenerator#GenerateProxyClass의 특정 소스 코드는 다음과 같습니다.
private byte [] generateClassFile () { / * * 1 단계 : 모든 메소드에 대한 proxymethod 객체를 조립하여 * 프록시 디스패치 코드를 생성합니다. */ // AddProxymethod 메소드 방법은 모든 메소드를 목록에 추가하고 해당 클래스에 해당하는 것입니다. // 객체, ToString 및 AddProxyMethod (HashcodemEthod, Object.class)에 해당하는 세 가지 방법이 있습니다. AddProxymethod (EqualSmethod, object.class); AddProxymethod (TostringMethod, Object.Class); // 인터페이스 목록의 인터페이스를 인터페이스 아래의 메소드와 비교합니다 (int i = 0; i <interfaces.length; i ++) {method [] method = interfaces [i] .getMethods (); for (int j = 0; }} / * * 동일한 서명이있는 각 프록시 메소드 세트에 대해 * 메소드의 리턴 유형이 호환되는지 확인하십시오. */ for (list <proxymethod> signmethods : proxymethods.values ()) {checkreturntypes (sigmethods); } / * * 2 단계 : 우리가 생성하는 클래스의 모든 필드 및 메소드에 대해 FieldInfo 및 MethodInfo Structs를 조립합니다. */// 하나의 생성자 인 메소드에 생성자 메소드를 추가하는데, 이는 invocationHandler 인터페이스가있는 생성자 인 하나의 생성자입니다 .//This는 클래스 파일, 즉 프록시 클래스에 메소드를 추가하는 실제 메소드입니다. 그러나 아직 처리되지 않았습니다. 먼저 추가되어 루프를 기다립니다. 클래스 파일의 생성자의 이름 설명은 <init> try {methods.add (geneateconstructor ()); for (list <proxymethod> signmethods : proxymethods.values ()) {for (proxymethod pm : signmethods) {// 각 프록시 메소드에 메소드 유형 속성을 추가합니다. 숫자 10은 클래스 파일의 식별자이며,이 속성은 fields.add (new FieldInfo (pm.methodfieldName, "ljava/lang/reflic/method;", acc_private | acc_static)임을 의미합니다. // 프록시 클래스 메소드 메소드에 각 프록시 메소드를 추가합니다 .add (pm.generatemethod ()); }} // 정적 초기화 블록을 추가하고 각 속성을 초기화합니다. 여기서 정적 코드 블록을 클래스 생성자라고도합니다. 실제로 <clinit> 이름이있는 메소드이므로 메소드 목록 메소드에 추가하십시오 (generatestaticinitializer ()); } catch (ioexception e) {새 NECTERNERROR ( "예기치 않은 I/O 예외"); } // 이전 인터페이스 수를 포함하여 메소드 및 속성 수는 65535를 초과 할 수 없습니다. // 클래스 파일 에서이 숫자는 4 비트 16 진수로 표시되므로 최대 값은 16th -1 인 경우 (methods.size ()> 65535) {Throw New ImperalArgumentException ( "메서드 한계 초과"); } if (fields.size ()> 65535) {New New OregalArgumentException ( "필드 한계 초과"); } // 다음 단계는 마술 번호, 클래스 이름, 상수 수영장 및 기타 일련의 바이트 코드를 포함한 클래스 파일을 작성하는 것입니다. 나는 세부 사항으로 들어 가지 않을 것입니다. 필요한 경우 JVM Virtual Machine Bytecode의 관련 지식을 참조하십시오. cp.getClass (dottoslash (className)); cp.getClass (SuperClassName); for (int i = 0; i <interfaces.length; i ++) {cp.getClass (dottoslash (인터페이스 [i] .getName ())); } cp.setReadOnly (); BYTEARRAYOUTPUTSTREAM BOUT = 새로운 BYTEARRAYOUTPUTSTREAM (); DataOutputStream dout = 새로운 DataOutputStream (Bout); {// u4 마술; dout.writeint (0xcafebabe); // u2 minor_version; dout.writeshort (classfile_minor_version); // u2 major_version; dout.writeshort (classfile_major_version); cp.write (dout); // (상수 풀 쓰기) // u2 access_flags; dout.writeshort (acc_public | acc_final | acc_super); // u2 this_class; dout.writeshort (cp.getClass (dottoslash (className))); // u2 super_class; dout.writeshort (cp.getClass (superclassName)); // u2 interfaces_count; dout.writeshort (인터페이스 .length); // u2 인터페이스 [interfaces_count]; for (int i = 0; i <interfaces.length; i ++) {dout.writeshort (cp.getclass (dottoslash (인터페이스 [i] .getname ())); } // u2 fields_count; dout.writeshort (fields.size ()); // field_info fields [fields_count]; for (fieldinfo f : fields) {f.write (dout); } // u2 method_count; dout.writeshort (methods.size ()); // method_info 메소드 [methods_count]; for (methodinfo m : methods) {m.write (dout); } // u2 attributes_count; dout.writeshort (0); // (프록시 클래스의 클래스 파일 속성 없음)} catch (ioException e) {새 NECTERNERROR ( "예기치 않은 I/O 예외"); } return bout.tobytearRay (); }통화 계층 후 프록시 클래스가 마침내 생성됩니다.
2. 누가 Invoke를 불렀습니까?
우리는 JDK를 시뮬레이션하여 프록시 클래스 자체를 생성하고 클래스 이름은 TestProxygen입니다.
public class testgeneratorproxy {public static void main (string [] args)은 ioexception {byte [] classfile = proxygenerator.generateproxyclass ( "testProxygen", goudring.class.getInterfaces ()); 파일 파일 = 새 파일 ( "/users/yadoao/goodtop/testproxygen.class"); fileoutputStream fos = 새 FileOutputStream (file); fos.write (classfile); fos.flush (); fos.close (); }}JD-Gui로 클래스 파일을 디 컴파일하면 결과는 다음과 같습니다.
import com.su.dynamicproxy.isubject; import java.lang.reflect.invocationHandler; import java.lang.reflect.method; import java.lang.reflect.proxy; import java.lang.reflect.undeclaredThrowablexception; Private Class Metterns Extends Proxy insuby insuby insublect {hamplect.reflect.method.method; 개인 정적 방법 M1; 개인 정적 방법 M0; 개인 정적 방법 M4; 개인 정적 방법 M2; public testproxygen (invocationHandler paraminVocationHandler) 던지기 {super (paraminvocationHandler); } public final void sayhello () 던지기 {try {this.h.invoke (this, m3, null); 반품; } catch (오류 | runtimeexception localError) {localError를 던지십시오; } catch (Throwable LocalThrowable) {새로운 미등성이없는 출시 (LocalThrowable); }} 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 int hashcode () 던지기 {try {return (returg) this.h.invoke (this, m0, null)). intvalue (); } catch (오류 | runtimeexception localError) {localError를 던지십시오; } catch (Throwable LocalThrowable) {새로운 미등성이없는 출시 (LocalThrowable); }} public final void saygoodbye () 던지기 {try {this.h.invoke (this, m4, null); 반품; } 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); }} static {try {m3 = class.forname ( "com.su.dynamicproxy.isubject"). getMethod ( "Sayhello", New Class [0]); m1 = class.forname ( "java.lang.object"). getMethod ( "equals", new class [] {class.forname ( "java.lang.object")); m0 = class.forname ( "java.lang.object"). getMethod ( "Hashcode", New Class [0]); m4 = class.forname ( "com.su.dynamicproxy.isubject"). getMethod ( "saygoodbye", new class [0]); m2 = class.forname ( "java.lang.object"). getMethod ( "Tostring", New Class [0]); 반품; } catch (nosuchmethodexception localNosuchMethodexception) {새로운 nosuchmethoderror (localnosuchmethodexception.getMessage ()); } catch (classNotFoundException LocalClassNotFoundException) {새 noclassDeffoundError (localClassNotFoundException.getMessage ()); }}} 먼저, 생성 된 프록시 클래스의 생성자가 invokehandler 인터페이스를 매개 변수로 구현하는 클래스에서 전달되고, 상위 클래스 프록시의 생성자라고 불렀으며, 이는 회원 변수 보호 된 invokehander h를 프록시에서 초기화했습니다.
나는 몇 가지 정적 초기화 블록을 다시 발견했습니다. 여기서 정적 초기화 블록은 프록시 인터페이스 목록 및 해시 코드, 토스트링 및 동등한 메소드를 초기화하는 것입니다.
마지막으로, 이러한 방법의 호출 프로세스가 있으며,이 모든 방법은 호출 메소드에 대한 콜백입니다.
이것은이 프록시 패턴의 분석으로 끝납니다.