1. 개요 <br /> 에이전트는 디자인 패턴이며, 그의 목적은 다른 객체에 특정 객체에 대한 액세스를 제어하기위한 프록시를 제공하는 것입니다. 프록시 클래스는 대의원 클래스의 전처리 메시지, 메시지 필터링 및 메시지 전달 및 메시지를 대의원 클래스에서 실행 한 후 후속 처리를 수행합니다. 행동의 일관성을 유지하기 위해 프록시 클래스와 대의원 클래스는 일반적으로 동일한 인터페이스를 구현합니다.
에이전트 생성 기간에 따르면 에이전트 클래스는 두 가지 유형으로 나눌 수 있습니다.
정적 프록시 : 프로그래머는 소스 코드를 자동으로 생성 한 다음 컴파일하는 프록시 클래스 또는 특정 도구를 만듭니다. 즉, 프록시 클래스의 .class 파일은 프로그램이 실행되기 전에 이미 존재합니다.
동적 프록시 : 반사 메커니즘을 사용하여 프로그램이 실행될 때 동적으로 생성하고 생성합니다.
동적 프록시 메커니즘을 구현하기 전에 정적 프록시를 간단히 소개하겠습니다.
2. 정적 프록시 <br /> 위에서 언급 한 바와 같이 프록시 클래스와 대의원 클래스는 일반적으로 동일한 인터페이스를 구현해야합니다. 다음은이 인터페이스를 먼저 정의하는 것입니다.
공개 인터페이스 서비스 {public void add ();}대의원 클래스는 인터페이스의 구현이며 다음과 같이 정의됩니다.
Public Class ServiceMpl은 서비스 {public void add () {System.out.println ( "Add User!"); }}대의원 클래스에 로그를 추가하려면 프록시 클래스는 다음과 같이 정의 할 수 있습니다.
공공 수업 서비스 프록시는 서비스 {개인 서비스 서비스; Public ServiceProxy (서비스 서비스) {super (); this.service = 서비스; } public void add () {system.out.println ( "서비스 시작"); service.add (); System.out.println ( "서비스 종료"); }}테스트 수업 작성 :
공개 클래스 테스트 메인 {public static void main (String [] args) {service servicempl = new ServiceMpl (); 서비스 프록시 = 새로운 ServiceProxy (ServiceImpl); proxy.add (); }}테스트 프로그램을 실행하면 결과는 다음과 같습니다.
위의 코드에서 정적 프록시 클래스가 특정 인터페이스 만 제공 할 수 있음을 알 수 있습니다. 여러 유형의 객체를 제공하려면 각 객체를 프록시해야합니다. 우리는 프록시 클래스를 통해 모든 프록시 기능을 완료 할 수 있는지 여부를 생각할 것이므로 동적 프록시의 개념을 소개했습니다.
3. Dynamic Proxy Java의 Dynamic Proxy는 주로 프록시와 호출 핸들러의 두 클래스가 포함됩니다.
프록시 : 인터페이스 세트에 대한 프록시 클래스와 해당 객체를 동적으로 생성하는 정적 메소드 세트를 제공합니다.
// 메소드 1 :이 메소드는 지정된 프록시 오브젝트와 관련된 통화 프로세서를 얻는 데 사용됩니다. static invocationHandler getInvocationHandler (Object Proxy) // 메소드 2 :이 메소드는 지정된 클래스 로더 및 인터페이스 세트와 관련된 동적 프록시 클래스의 클래스 객체를 얻는 데 사용됩니다. 정적 클래스 GetProxyClass (클래스 로더 로더, 클래스 [] 인터페이스) // 메소드 3 :이 메소드는 지정된 클래스 객체가 동적 프록시 클래스 정적 부울 ISProxyClass (클래스 CL)인지 결정하는 데 사용됩니다. 방법 4 :이 방법은 지정된 클래스로드에 동적 프록시 클래스 인스턴스를 생성하는 데 사용됩니다. 정적 객체 NewProxyInstance (클래스 로더 로더, 클래스 [] 인터페이스, invocationHandler h)
InvocationHandler : 호출 프로세서 인터페이스로, 호출 메소드를 사용자 정의하며 동적 프록시 클래스 객체에서 메소드 호출을 중앙에 처리하는 데 사용됩니다.
//이 메소드는 동적 프록시 클래스에서 모든 메소드 호출을 중앙에 처리하는 책임이 있습니다. 첫 번째 매개 변수는 프록시 클래스의 인스턴스이고 두 번째 매개 변수는 // 세 번째 메소드가 호출 매개 변수입니다. 통화 프로세서 전송 사전 처리 또는 대의원 클래스 인스턴스로 발송하여 실행 객체 호출 (객체 프록시, 메소드 메소드, 개체 [] args)
Java 용 Dynamic Proxy를 구현하려면 네 가지 특정 단계가 있습니다.
1. InvocationHandler 인터페이스를 구현하여 고유 한 통화 프로세서 작성
2. 클래스 로더 객체와 프록시 클래스의 인터페이스 세트를 지정하여 동적 프록시 클래스를 만듭니다.
3. 반사 메커니즘을 통해 동적 프록시 클래스의 생성자를 얻고 유일한 매개 변수 유형은 Call Processor 클래스 인터페이스 유형입니다.
4. 생성자를 통해 동적 프록시 클래스 인스턴스를 만듭니다. 시공 중에 프로세서 객체를 매개 변수라고하며 전달됩니다.
다음은 위의 네 단계를 기반으로 자신의 동적 프록시를 구현하는 예입니다.
인터페이스 및 인터페이스의 구현 클래스 (즉, 대표 클래스)는 위 정적 프록시의 코드와 동일합니다. 여기서는 호출 처리기 인터페이스를 구현하여 고유 한 통화 프로세서를 생성합니다.
공개 클래스 서비스 핸들은 invocationHandler {private object s; 공공 서비스 핸들 (객체) {this.s = s; } public Object Invoke (오브젝트 프록시, 메소드 메소드, 개체 [] args) 던지기 가능 {System.out.println ( "Service Start"); // 호출은 지정된 매개 변수가있는 지정된 객체 에서이 메소드 객체로 표시되는 기본 메소드를 호출하는 것을 의미합니다. 객체 result = method.invoke (s, args); System.out.println ( "서비스 종료"); 반환 결과; }}테스트 수업 작성 :
공개 클래스 테스트 메인 {public static void main (String [] args) {service service = new ServiceMpl (); invocationHandler handler = new ServiceHandle (서비스); Service S = (Service) proxy.newProxyInstance (service.getClass (). getClassLoader (), service.getClass (). getInterfaces (), handler); s.add (); }}테스트 프로그램을 실행하면 결과는 정적 프록시와 동일합니다. Prox의 정적 방법 NewProxyInstance 가이 두 단계를 캡슐화했기 때문에 위의 코드에는 앞에서 언급 한 단계 2와 3이 없음을 알 수 있습니다. 특정 내부 구현은 다음과 같습니다.
// 프록시 클래스 클래스를 통한 인터페이스 인터페이스를 포함하여 인터페이스 인터페이스를 포함하여 인터페이스 클래스의 클래스 객체를 동적으로 생성합니다. clazz = proxy.getProxyClass (classloader, new class [] {interface.class, ...}); // 반사 구성 제작자에서 생성 된 클래스 객체를 통해 생성 된 클래스 객체를 획득하십시오. }); // 생성자 객체 인터페이스 프록시를 통해 동적 프록시 클래스 인스턴스를 만듭니다.NewProxyInstance 함수의 내부 구현은 다음과 같습니다.
public static 객체 NewProxyInstance (클래스 로더 로더, 클래스 <?> [] 인터페이스, invocationHandler h)는 불법 행위 값을 던진다. // 클래스 로더 및 인터페이스 세트 세트와 관련된 프록시 클래스 유형 객체를 가져옵니다. 최종 클래스 <?> [] intfs = interfaces.clone (); // 인터페이스 클래스 객체가 클래스 로더에 보이는지 여부를 확인하고 클래스 로더에서 인식하는 인터페이스 클래스 객체와 정확히 동일합니다. 최종 보안 관리자 sm = system.getSecurityManager (); if (sm! = null) {checkProxyAccess (reflection.getCallerClass (), 로더, intfs); } // 클래스 로더 및 인터페이스 세트 세트와 관련된 프록시 클래스 유형 객체를 가져옵니다 클래스 <?> cl = getProxyClass0 (로더, intfs); try {if (sm! = null) {checknewProxyPermission (reflection.getCallerClass (), cl); } // 반사를 통해 생성자 객체를 가져 와서 프록시 클래스 인스턴스 최종 생성자 <?> cons = cl.getConstructor (ConstructorParams); 최종 호출 핸들러 ih = h; if (! modifier.ispublic (cl.getModifiers ())) {accessController.Doprivileged (새 권한 <void> () {public void run () {cons.setAccessible (true); return null;}}); } return cons.newinstance (new Object [] {h}); } catch (INSERGALACCESSException | instantiationException e) {새로운 내부 테러 (e.toString (), e); } catch (invocationTargeteXception e) {Throwable t = e.getCause (); if (t instanceof runtimeexception) {trash (runtimeexception) t; } else {Throw New InternalError (t.toString (), t); }} catch (nosuchmethodexception e) {새 ninternerror (e.toString (), e); }} 4. 프록시 클래스 시뮬레이션 및 구현
위의 원칙 소개에 따르면, 우리는 스스로 프록시 클래스를 시뮬레이션하고 구현할 수 있습니다.
공개 클래스 프록시 {public static object NewProxyInstance (클래스 inface, invocationHandle h) 예외 {String rt = "/r/n"; 문자열 methodstrs = ""; 메소드 [] 메소드 = inface.getMethods (); for (method m : methods+= "@attomperride"+rt+"public void"+m.getname ()+"()"+rt+"{"+rt+"try {"+rt+"method md ="+inface.getname ()+". class.getMethod (/" "+M. m. m. m.getname ()+"); "+rt+"); "h.invoke (this, md);"+ rt+ "} catch (예외 e) {e.printstacktrace ();}"+ rt+ "}"; } 문자열 src = "패키지 테스트;"+ rt+ "import java.lang.reflect.method;"+ rt+ "public class serviceimpl2 구현"+ inface.getname ()+ rt+ "{"+ rt+ "public serviceimpl2 (invocationHandle h)"+ rt+ "{"+ rt+ "h; test.invocationHandle h; "+ rt+ methodstr+"} "; 문자열 filename = "d : /src/test/serviceimpl2.java"; // 컴파일 컴파일 (src, filename); // 메모리에로드하고 인스턴스 객체를 만듭니다. m = loadMemory (h); 반환 m; } private static void compile (String Src, String Filename)은 ioexception {file f = 새 파일 (filename); filewriter filewriter = 새로운 filewriter (f); filewriter.write (SRC); filewriter.flush (); filewriter.close (); //이 플랫폼에서 제공 한 Java 컴파일러를 가져옵니다. // 표준 파일 관리자가 구현 한 새 인스턴스를 가져옵니다. StandardJavaFileManager filemanager = compiler.getStandardFileManager (NULL, NULL, NULL); // 주어진 파일을 나타내는 파일 객체를 가져옵니다. 반복 가능한 단위 = filemanager.getJavafileObjects (filename); // 향후 컴파일 테스크 생성 t = compiler.getTask (null, filemanager, null, null, null, units); //이 컴파일 작업을 실행합니다. t.call (); filemanager.close (); } private static 객체로드 메모리 (invocationHandle h)는 층류가 발생하여 classNotFoundException, noSuchMethodexception, InstantiationException, 불법 행위 exception, invoctionTargetexception {url [] urls = new url [] {new url ( "file :/"+"d :/src/"); //로드 클래스 및 리소스 URLCLASSLOADER UL = New UrlClassLoader (URLS); 클래스 C = ul.loadclass ( "test.serviceimpl2"); // 클래스 객체로 표시된 클래스의 지정된 공개 생성자를 반환합니다. 생성자 ctr = c.getConstructor (invocationHandle.class); //이 생성자 객체 CTR로 표시된 생성자 메소드를 사용하여 생성자 메소드의 선언 클래스의 새 인스턴스를 생성하고 지정된 초기화 매개 변수 개체 객체 M = Ctr.NewInstance (h)로 인스턴스를 초기화합니다. 반환 m; }}5. 요약 1. 소위 다이내믹 프록시는 그러한 클래스입니다. 런타임에 생성 된 클래스입니다. 그것을 생성 할 때는 인터페이스 세트를 제공 한 다음 클래스를 변경하여 이러한 인터페이스를 구현한다고 주장해야합니다. 그러나 실질적인 작업을 수행하지는 않지만 인스턴스를 생성 할 때 제공되는 매개 변수 핸들러 (즉, InvociationHandler 인터페이스의 구현 클래스)를 기반으로 실제 작업을 인수합니다.
2. Proxy의 디자인은 인터페이스 프록시 만 지원합니다. Java의 상속 메커니즘은 동적 프록시 클래스가 클래스를위한 동적 프록시를 구현할 수 없다는 것이 예정되어 있습니다.
위의 내용은이 기사에 관한 모든 것입니다. 모든 사람의 학습에 도움이되기를 바랍니다.