기본 사항 : 객체 지향 디자인 아이디어, 다형성 아이디어 및 반사 아이디어가 필요합니다.
Java Dynamic Proxy 메커니즘의 출현으로 Java 개발자는 프록시 클래스를 수동으로 작성하지 않고도 프록시 클래스를 동적으로 얻을 수 있습니다. 프록시 클래스는 실행을 반영하기 위해 모든 메소드 호출을 대리인 객체로 발송해야합니다. 디스패치 실행 프로세스 중에 개발자는 대의원 객체와 필요에 따라 기능을 조정할 수도 있습니다. 이것은 매우 유연하고 유연한 프록시 프레임 워크입니다. 이 기사를 읽음으로써 독자들은 Java Dynamic Proxy 메커니즘을 더 깊이 이해할 수 있습니다. 이 기사는 먼저 Java Dynamic Proxy의 운영 메커니즘 및 특성을 기반으로 코드를 분석하고 동적 생성 클래스의 내부 구현을 추론합니다.
에이전트 모델의 기본 개념 및 분류
프록시 모드 : 다른 객체 가이 객체에 대한 액세스를 제어 할 프록시를 제공합니다. 프록시 객체는 중개자 역할을하며 서비스를 제거하거나 추가 서비스를 추가하거나 다른 서비스를 추가 할 수 있습니다. "프록시 클래스는 대의원 클래스 및 메시지 필터링 및 전달 메시지를위한 미리 처리 메시지를 담당하며 메시지를 대의원 클래스에서 실행 한 후 후속 처리를 수행합니다."
개발중인 에이전트 모드의 응용 프로그램 시나리오
원격 프록시 : 다른 지역의 객체에 대한 LAN 대표 객체를 제공합니다.
가상 에이전트 : 필요에 따라 많은 리소스를 소비하는 객체를 지연시키고 실제로 필요할 때 만들 수 있습니다. 예를 들어, 텍스트가 먼저 표시되면 사진이 웹 페이지에 표시됩니다.
보호 에이전트 : 다른 사용자의 액세스 권한을 제어합니다. 예를 들어, 고객 등록이 성공한 후에 만 추가, 삭제, 수정 및 확인 작업을 수행 할 수 있습니다.
스마트 참조 에이전트 : 대상 에이전트에 추가 서비스를 제공합니다.
프록시 모드를 구현하는 방법
상속 및 집계를 사용하여 동적 프록시를 구현하는 것이 더 좋습니다!
public interface moveable {public void move ();} public class car emperments movable {@override public void move () {try {thread.sleep (new random (). nextInt (1000)); System.out.println ( "... Driving ...");} catch (InterruptedException e) {// auto-getrated catch bloc. car {@override public void move () {// 코드를 분리하고 비즈니스 로직을 늘리고 비즈니스 로직을 늘립니다. Long Starttime = System.currentTimeMillis (); System.out.println ( "차가 운전하기 시작합니다 ..."); Super.Move (); System.CurrentTimEmillis (); System.out.println ( "차량으로 끝납니다. "+(endtime-starttime)+"ms ");}}프록시를 구현하는 상속 방법
Moveablecar2=newCar2();
car2.move();
집계 방법은 프록시를 구현합니다
Carcar=newCar();
Moveablem=newCar3(car);
m.move();
요약
상속 방법은 충분히 유연하지 않습니다. 함수가 중첩되면 프록시 클래스를 부풀게 확장 할 수 있습니다.
응집을 사용하여 에이전트를 서로 전달할 수 있으며 프록시는 유연하게 결합 될 수 있습니다.
Public Class Carlogproxy는 CAR {@Override public void move () {// 코드를 분리하고 비즈니스 로직을 분리하고 비즈니스 로직을 늘리고 System.CurrentTimeMillis ( "System.out.println ("Login Start ... "); Super.Move (); long endtime = System.CurrentTimeMillis (); System.out.println ("System.out.println ( "); Cartimeproxy는 움직일 수있는 {public cartimeproxy (car car) {super (); this.car = car;} private carcar; @override public void move () {// 코드를 분리하고 비즈니스 로직 Long StartTime = System.CurrentTimeMillis (); "자동차가 운전하기 시작합니다 ..."; endtime = System.CurrentTimeMillis (); System.out.println ( "자동차는 운전으로 끝납니다 ... 시간 :"+(EndTime-StartTime)+"MS");}}}}@test : car car = new car (); carlogproxy clp = carlogprogproxy (ctp.); 또한 인터페이스 Carlogproxy Clp1 = 새로운 Carlogproxy (CAR); CartimeProxy CTP1 = New CartimeProxy (CLP1); CTP1.Move ();JDK 다이내믹 프록시 및 CGLIB 다이내믹 프록시
JDK 동적 프록시
에이전트 구현
다른 객체가 동일한 함수로 프록시 클래스를 구현하려면 어떻게해야합니까?
현재 동일한 프록시 클래스 ------ 동적 프록시에 통합하려고 시도 할 수 있습니다. 다른 클래스/다른 방법에 대한 프록시 구현;
일반적인 과정은 다음과 같습니다.
Java Dynamic Proxy 클래스는 Java.lang.reflect 패키지 아래에 있으며 일반적으로 다음 두 클래스가 포함됩니다.
(1) InterfaceInvocationHandler :이 인터페이스에서 하나의 메소드 만 정의됩니다. PublicoBjectInvoke (ObjectObj, MethodMethod, Object [] args)
OBJ : 일반적으로 프록시 클래스를 나타냅니다
방법 : 프록시 방법입니다
Args는이 방법에 대한 매개 변수 배열입니다.
이 추상 방법은 프록시 클래스에서 동적으로 구현됩니다.
(2) 프록시 :이 클래스는 역동적 인 프록시 클래스입니다
statixObjectnewProxyInstance(ClassLoaderloader,Class[]interfaces,InvocationHandlerh)
글리코 사이드 클래스의 인스턴스를 반환하면 반환 된 프록시 클래스는 프록시 클래스로 사용할 수 있습니다 (프록시 클래스에서 인터페이스에서 선언 된 메소드를 사용할 수 있음).
구현 예 :
@ timehandler public class timehandler는 invocationhandler {public timehandler (Object Targe) {super (); super (); super (); this.target = target;} private objecttarget;/** 매개 변수 :* 프록시 프록시 객체* 프록시 객체* args 매개 변수** 객체 반환 값*/@ arge grows s (대상, 대상, 대상, 대상) startTime = System.CurrentTimeMillis (); System.out.println ( "차가 운전하기 시작합니다 ..."); Method.Invoke (Target); Long Endtime = System.CurrentTimEmillis (); System.out.println ( "차량이 시간 :"+(EndTime-StartTime)+"MS"); Return Null;}}}}}}} @프록시 클래스 공개 인터페이스의 인터페이스 이동 가능 {public void move ();}@The Proxy 클래스 공개 클래스 자동차는 움직일 수있는 {@override public void move () {try {thread.sleep (new random (). NextInt (1000)); System.out.println ( "... Driving ...");} catch (InterpruptedException e) {// todo auto-auto-Generated Catch E.PrintStackTrace ();}}}}}}}}}}@시험
공개 클래스 테스트 { / *** JDK 동적 프록시 테스트 클래스* / public static void main (String [] args) {Car Car = new Car (); invocationHandler h = 새로운 시간 핸들러 (CAR); 클래스 <?> cls = car.getClass (); /** 로더 클래스 로더* 인터페이스 인터페이스를 구현* h revocationHandler*/ moveable m = (movable) proxy.newProxyInstance (cls.getClassLoader (), cls.getInterfaces (), h); M.Move (); }}&& 테스트 결과
요약
DynamicProxy는 다음과 같은 클래스입니다.
런타임에 생성 된 클래스입니다. 이 클래스는 인터페이스 세트를 구현해야합니다. 동적 프록시 클래스를 사용하는 경우 InvocationHandler 인터페이스를 구현해야합니다.
JDK 동적 프록시를위한 일반적인 단계
1. Interface invocationHandler를 구현하는 클래스를 만듭니다.
2. 프록시 클래스와 인터페이스를 만듭니다
3. 프록시의 정적 메소드를 호출하여 프록시 클래스를 만듭니다.
NewProxyInstance (ClassLoaderLoader, Class [] 인터페이스, invocationHandlerh)
4. 프록시를 통한 메소드를 호출하십시오
CGLIB 동적 프록시 구현
에이전트 구현
@introducting cglib-node-2.2.jar 패키지
@cglibproxy intercept 클래스는 인터페이스 메소드 인터셉트를 구현합니다 : 인터셉트 메소드를 다시 작성하십시오
public class cglibproxy는 Methodinterceptor {private enhancerenhancer = new enhancer (); public object getProxy (클래스 Cl) {// 서브 클래스 enhancer.setSuperClass (cl)를 생성하는 클래스를 설정합니다. Args Method* 프록시 클래스의 프록시 인스턴스*/@public Object Intercept (Object obj, method m, object [] args, methodproxy proxy)가 던질 수있는 {system.out.println ( "로그인 시작 ..."); // 프록시 클래스는 부모 클래스의 메소드를 대하 메소드를 호출합니다. null;}}@proxy 클래스 열차
공개 클래스 열차 {public void move () {System.out.println ( "기차가 운전 중 ..."); }}@Test 클래스
공개 클래스 테스트 { / *** cglibproxy 동적 프록시 테스트 클래스* / public static void main (String [] args) {cglibproxy proxy = new cglibproxy (); Train t = (기차) proxy.getProxy (Train.class); t.move (); }}## 테스트 결과 :
요약
cglibproxy를 사용하여 동적 프록시를 구현하는 일반 단계
1. 인터페이스 메소드 인 트리처를 구현하고 인터셉트 메소드를 재정의하는 클래스를 만듭니다.
2. 프록시 클래스를 만듭니다
3. 프록시 클래스 사용자 정의 메소드에 전화하여 프록시 인스턴스를 얻으십시오.
4. 프록시 인스턴스에서 실행 해야하는 메소드를 호출하십시오.
비교 요약
JDK 동적 프록시
1. 인터페이스를 구현하는 프록시 클래스 만
2. 인터페이스가없는 클래스 JDK 용 동적 프록시를 구현할 수 없습니다.
CGLIB 동적 프록시
1. 클래스 프록시 구현
2. 실행 대상 클래스에 서브 클래스를 생성하고 메소드를 가로 지르는 기술을 사용하여 모든 상위 클래스 메소드 호출을 가로 채립니다.
에이전트 생성 단계를 시뮬레이션하십시오
아이디어 :
구현 함수 : 프록시의 NewProxyInstance를 통해 프록시 오브젝트를 반환합니다
1. 소스 코드 선언 (동적 생성 에이전트)
2. 새 클래스 (프록시 클래스)를 생성하려면 소스 코드 (jdkcompilerapi)를 컴파일합니다.
3.이 클래스를 메모리에로드하고 새 개체 (프록시 객체)를 생성합니다.
4. 프록시 객체를 반환합니다
동적 프록시 구현을 향상시킵니다
먼저 시스템 컴파일러를 얻고 컴파일러를 통해 파일 관리자를 가져온 다음 파일을 가져옵니다. 그런 다음 컴파일러는 컴파일 작업을 수행합니다. 컴파일을 완료 한 후 클래스 파일을 클래스 로더에로드하고 생성자 메소드를 통해 인스턴스를 얻은 다음 NewInstance ()를 호출하여 객체의 인스턴스를 수신합니다.
(1) 컴파일러 JavaCompilerCompiler = ToolProvider.getSystemjavacompiler ();
(2) 파일 관리자 표준 javafilemanagerfilemgr = compiler.getStandardFileManager (NULL, NULL, NULL);
(3) 파일 iterableUnits = filemgr.getjavafileobjects (filename)를 가져옵니다.
(4) 컴파일 작업 CompilationTaskt = Compiler.getTask (NULL, FILEMGR, NULL, NULL, NULL, NULL, UNITS);
(5) 메모리로드
classloadercl = classloader.getSystemClassLoader ();
classc = cl.loadclass ( "com.imooc.proxy. $ proxy0");
(6) 프록시 개체의 생성자를 통해 인스턴스 구성
constructorctr = c.getConstructor (infce);
ctr.newinstance (newcar ());
--------
위에서 언급했듯이 내부 비즈니스 논리는 하드 코딩되었습니다. 실제 동적 프록시 및 동적으로 지정된 비즈니스 로직을 구현하는 방법은 무엇입니까?
1. 트랜잭션 프로세서를 작성해야합니다. 먼저 인터페이스, 즉 InvocationHandler를 만듭니다. JDK를 시뮬레이션하기 위해 인터페이스의 이름은 JDK 트랜잭션 프로세서의 이름과 동일합니다. 또한 비즈니스 처리를위한 객체의 특정 메소드를 나타내는 데 사용되는 invoke ()라는 메소드도 작성합니다. 따라서 invoke () 메소드의 매개 변수로 특정 객체와 객체의 메소드를 전달해야합니다. Java 반사의 매개 변수로 사용 된 방법 인 Invoke (Objectobj, MethodMethod)를 호출 하고이 패키지를 도입해야합니다. 이러한 방식으로 invocationhandler 인터페이스가 완료됩니다.
2. TimerProxy와 같은 트랜잭션 처리 구현 클래스를 작성하여 호출 핸들러 인터페이스를 구현하여 구조가됩니다.
- - - - - - TimerproxyimplementsInvocationHandler { ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――�대상 객체를 전달해야합니다. 매개 변수가없는 경우 매개 변수를 쓸 수 없습니다. 프록시 객체 구성 방법을 작성하고 대상 객체를 초기화하십시오.
3. 프록시 클래스의 NewProxyInstance () 메소드에서 대상 클래스 인터페이스를 매개 변수로 사용하는 것 외에도 트랜잭션 프로세서 invoctionHandler를 전달한 다음 생성 된 인스턴스 객체의 하드 코드 부분을 변경하고 트랜잭션 프로세서 메소드를 사용하여 교체해야합니다. 어려움은 현의 접합에 있습니다.
요약
우리 프로젝트에서 에이전트 패턴은 고유 한 중요한 의미를 갖습니다. 예를 들어, 특정 JAR 패키지 아래에서 클래스를 호출하려면이 클래스를 호출하기 전에 특수 비즈니스 로직을 추가 할 수 있습니다. 이 방법을 AOP 중심 프로그래밍이라고도합니다. (원래 기능을 변경하지 않고 추가 기능을 추가하십시오.)
위는이 기사에서 Java Dynamic Proxy (Design Pattern) 코드에 대한 자세한 설명입니다. 모든 사람에게 도움이되기를 바랍니다. 관심있는 친구는이 사이트의 다른 관련 주제를 계속 참조 할 수 있습니다. 단점이 있으면 메시지를 남겨 두십시오. 이 사이트를 지원해 주신 친구들에게 감사드립니다!