자바 동적 에이전트 정적 에이전트 실례 분석

프 록 시 모드:다른 대상 에 게 프 록 시 를 제공 하여 특정한 대상 의 접근 을 제어 합 니 다.사용:특정한 상황 에서 한 고객 이 다른 대상 을 직접 방문 하고 싶 지 않 거나 방문 할 수 없 으 며 대리 대상 은 클 라 이언 트 와 목표 대상 전에 중개 역할 을 할 수 있 고 대리 대상 은 추가 적 인 작업 을 완성 할 수 있 습 니 다.
예:집주인,세입 자,중개 와 같은 관계.중개(대리 대상)는 집주인(진실 대상)이 집 을 임대 하고 세입 자(고객)는 중개(대리 대상)를 통 해 집 을 찾 아 전 세 를 구하 고,중 개 는 전 세 를 마치 면 중개 수수료(부가 조작)를 받 을 수 있다.
먼저 정적 프 록 시 모드 를 살 펴 보고 위 에서 프 록 시 모드 에 대한 이 해 를 통 해 프 록 시 모드 를 알 수 있 습 니 다.즉,new 의 실제 대상 을 통 해 방법 을 호출 하지 않 고 프 록 시 대상 을 통 해 방법 을 호출 하기 때문에 프 록 시 대상 은 실제 대상 의 인용 을 포함 합 니 다.코드 를 보 겠 습 니 다.
인터페이스:Subject 는 하나의 방법 을 포함 합 니 다.

 package com.example.designpattern.proxy; 
 public interface Subject {
 void request();
 }
RealSubject 클래스 는 Subject 인 터 페 이 스 를 실 현 했 습 니 다.간단하게 보기 위해 방법 은 간단하게 한 마디 를 출력 합 니 다.

package com.example.designpattern.proxy;
public class RealSubject implements Subject {
//       
public void request() {
System.out.println("From real subject");
}
}
프 록 시 클래스 Proxy Subject 도 Subject 인 터 페 이 스 를 실현 하고 Subject 안의 방법 을 실현 해 야 하지만 여기 서 는 실제 대상 을 호출 하여 이 루어 집 니 다.

package com.example.designpattern.proxy;

public class ProxySubject implements Subject {

private RealSubject realSubject; //             

//          
public void request() {

this.preRequest(); //               
if (realSubject == null){
realSubject = new RealSubject();
}
realSubject.request(); //           
this.afterRequet(); //              
}
//           
private void preRequest(){
System.out.println("pre request");
}
//           
private void afterRequet(){
System.out.println("after request");
}
}
클 라 이언 트 호출 자

package com.example.designpattern.proxy;

public class Client {
public static void main(String[] args) {
ProxySubject proxy = new ProxySubject();
//           
proxy.request(); 
}
}
정적 에이전트:
이 코드 들 을 실행 할 수 있 습 니 다.Client 클래스 에서 볼 수 있 습 니 다.프 록 시 Subject 의 대상 proxy 를 통 해 호출 하 는 방법 입 니 다.프 록 시 클래스 Proxy Subject 에서 실제 대상 의 인용 이 있 고 프 록 시 대상 에서 request()방법 으로 실제 대상 의 방법 을 호출 했 습 니 다.이런 모델 을 대리 모델 이 라 고 한다.
장점 은:
1.프 록 시 모드 는 프 록 시 대상 과 실제 대상 이 호출 된 대상 을 분리 할 수 있 습 니 다.
2.어느 정도 시스템 의 결합 도 를 낮 추고 확장 성 이 좋다.
프 록 시 클래스 에는 실제 주제 에 대한 인용 이 포함 되 어 있 습 니 다.이렇게 하 는 것 도 단점 이 있 습 니 다.
1.실제 대상 과 대리 류 가 일일이 대응 하고 진실 류 를 증가 하 는 것 도 대리 류 를 증가 해 야 한다.이렇게 하면 유형의 수량 을 신속하게 증가 시 켜 시스템 을 복잡 하 게 만 들 수 있다.
2.디자인 대리 이전에 실제 주 제 는 반드시 사전에 존재 해 야 하고 유연성 이 없다.
동적 대 리 를 사용 하면 상기 문 제 를 해결 할 수 있 습 니 다.동적 대 리 는 정적 대리 에 비해 서 입 니 다.
동적 생 성 인 스 턴 스 를 어떻게 실현 하 는 지 말 할 수 있 습 니 다.이전에 우리 가 만 든 인 스 턴 스 는 모두 new 방식 으로 이 루어 지지 않 았 습 니까?
Hello hi = new Hello();
그러면 동적 생 성 인 스 턴 스 는 자바 가 제공 하 는 기능 이 므 로 우리 가 new 대상 에 갈 필요 가 없습니다.그 는 정적 방법 인 Proxy.new Proxy Instance()를 정 의 했 습 니 다.매개 변수 호출 만 들 어 오 면 됩 니 다.자바 문서 에 있 습 니 다.그림 참조:

자바 표준 라 이브 러 리 는 동적 에이전트(DynamicProxy)의 메커니즘 을 제공 합 니 다.실행 기간 동안 특정한 interface 의 인 스 턴 스 를 동적 으로 만 들 수 있 습 니 다.
매개 변수 설명:

 Proxy.newProxyInstance(
 ClassLoader loader, //   ClassLoader
 Class<?>[] interfaces, //              
 InvocationHandler h); //  InvocationHandler    
다음은 동적 에이전트 예 코드 를 보 겠 습 니 다.
Subject 인터페이스

package design.dynamicproxy;
public interface Subject {
void request(String str);
}
RealSubject 클래스 구현 Subject 인터페이스

package design.dynamicproxy;
public class RealSubject implements Subject {
@Override
public void request(String str) {
System.out.println("From Real Subject!" + " args:" + str );
}
}
동적 에이전트 류 DynamicSubject 는 Invocation Handler 를 실현 하고 invoke()방법 을 다시 작성 합 니 다.

package design.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
*           Object  ,     ,               
*         invoke()   ,     method.invoke()                    
*      object,        object  ,       ,            
*                
*/
public class DynamicSubject implements InvocationHandler {

//      Object ,            
private Object object;

public DynamicSubject(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before calling:" + method);
//   realSubject request()   ,         ,    Method       
method.invoke(object, args);
System.out.println("after calling:" + method);
return null;
}
}
클 라 이언 트 클래스

package design.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Client {
	public static void main(String[] args) {
		RealSubject realSubject = new RealSubject();
		InvocationHandler handler = new DynamicSubject(realSubject);
		Class<?> classType = handler.getClass();
		//            
		//      class com.sun.proxy.$Proxy0    ,
		Subject subject = (Subject) Proxy.newProxyInstance(classType.getClassLoader(), realSubject.getClass().getInterfaces(),handler);
		subject.request("eather");
		System.out.println(subject.getClass());
		//  class com.sun.proxy.$Proxy0,    Proxy.newProxyInstance()           
	}
}
Client 에서 볼 수 있 습 니 다.여기 서 호출 하 는 방법 은 subject.request("eather")입 니 다.이 대상 subject 는 new DynamicSubject()를 통 해 생 성 된 것 이 아니 라 자바 내부 에서 작성 한 방법 으로 실 행 될 때 동적 으로 대상 을 생 성 합 니 다.이 가능 하 다,~할 수 있다,...InvocationHandler handler = new DynamicSubject(realSubject);여 기 는 new DynamicSubject(realSubject)를 통 해 가 아 닙 니 다.대상 이 생 겼 나 요?네,그렇지만 Invocation Handler 형식 입 니 다.주로 Invocation Handler 형식 인 자 를 Proxy.new Proxy Instance()에 전달 합 니 다.마지막 인자 입 니 다.클 라 이언 트 클래스 의 마지막 출력 을 통 해 클 라 이언 트 com.sun.proxy.$Proxy 0 을 볼 수 있 습 니 다.이것 은 자바 가 실 행 될 때 생 성 된 것 입 니 다.
정적 에이전트 의 어 려 운 문 제 를 해결 했다.1.실제 대상 과 대리 류 가 일일이 대응 하고 진실 류 를 증가 하 는 것 도 대리 류 를 증가 해 야 한다.이렇게 하면 유형의 수량 을 신속하게 증가 시 켜 시스템 을 복잡 하 게 만 들 수 있다.왜 이렇게 말 합 니까?프 록 시 클래스 가 인용 하 는 유형 은 Object 이기 때문에 모든 대상 에 마음대로 들 어 갈 수 있 습 니 다.실제 클래스 가 증가 할 때 프 록 시 클래스 는 증가 하지 않 아 도 됩 니 다.new DynamicSubject(object);new 때 들 어 올 대상 을 들 여 보 내 면 됩 니 다.
다음은 프 록 시 뉴 프 록 시 인 스 턴 스(ClassLoader loader,Class[]interfaces, InvocationHandler h); 이 방법의 소스 코드 는 볼 수 있 고 깊이 이해 할 수 있다.

public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
	Objects.requireNonNull(h);
	final Class<?>[] intfs = interfaces.clone();
	final SecurityManager sm = System.getSecurityManager();
	if (sm != null) {
		checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
	}
	/*
* Look up or generate the designated proxy class.
         
*/
	Class<?> cl = getProxyClass0(loader, intfs);
	/*
* Invoke its constructor with the designated invocation handler.
                  。    InvocationHandler     【         】     
*/
	try {
		if (sm != null) {
			checkNewProxyPermission(Reflection.getCallerClass(), cl);
		}
		final Constructor<?> cons = cl.getConstructor(constructorParams);
		final InvocationHandler ih = h;
		if (!Modifier.isPublic(cl.getModifiers())) {
			AccessController.doPrivileged(new PrivilegedAction<Void>() {
				public Void run() {
					cons.setAccessible(true);
					return null;
				}
			}
			);
		}
		return cons.newInstance(new Object[]{
			h
		}
		);
	}
	catch (IllegalAccessException|InstantiationException e) {
		throw new InternalError(e.toString(), e);
	}
	catch (InvocationTargetException e) {
		Throwable t = e.getCause();
		if (t instanceof RuntimeException) {
			throw (RuntimeException) t;
		} else {
			throw new InternalError(t.toString(), t);
		}
	}
	catch (NoSuchMethodException e) {
		throw new InternalError(e.toString(), e);
	}
}
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기