Java 디자인 모드 - 동적 프록시 모드

3556 단어 java 학습 노트

프록시 모드


프록시 모드의 의도는 인터페이스나 자리 차지 문자를 통해 대상에 대한 접근을 제어하는 것이다
대리 대상은 보통 실제 대상과 같은 인터페이스를 가지고 있으며, 제어 방문을 통해 요청을 합리적으로 밑바닥의 실제 대상에게 전달한다

동적 에이전트 (에이전트가 필요한 클래스가 인터페이스를 실현함)


반사 클래스 Proxy와 InvocationHandler 리셋 인터페이스를 통해
동적 에이전트는 에이전트 대상을 통해 실제 대상을 포장하고 에이전트 대상을 통해 실제 대상에 대한 요청을 차단한 다음에 에이전트로 실제 대상에게 전송하며 호출을 차단하기 전이나 이후에 자신의 코드를 추가할 수 있도록 한다

동적 에이전트 만들기


(1) 실제 대상이 실현하는 모든 인터페이스를 얻는다.obj가 실제 대상입니다.
Class[] classes=obj.getClass().getInterfaces();
(2) 실제 대상이 속한 클래스를 획득하는 클래스 캐리어
ClassLoader loader=obj.getClass().getClassLoader();
(3) 프록시 객체 작성 자체
이 대상 소속 클래스는java를 실현해야 합니다.lang.reflect 패키지의 InvocationHandler 커넥터입니다.이 인터페이스에서 invoke 방법을 정의했습니다
다음:InvocationHandler 인터페이스를 실현하여 invoke 방법을 다시 쓰고result=method.voke(obj,args) 이 줄은 반사를 통해 목표를 실제 대상에게 호출하여 전송하는 것이다. 전송 전후에 코드를 추가하고 간단한 로그 기능을 실현하면 프록시 클래스가 만들어진다.
package xidian.lili.edu.proxy;

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

public class ImpatientProxy implements InvocationHandler{
	private Object obj;
	public ImpatientProxy(Object obj){
		this.obj=obj;
	}
	@Override
	public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
		Object result;
		long t1=System.currentTimeMillis();
		result=method.invoke(obj, args);
		long t2=System.currentTimeMillis();
		System.out.println("It takes "+(t2-t1)+" millis to invoke "+method.getName());
		return result;
	}
}

그러면 프록시 클래스 ImpatientProxy의 대상을 사용하려면java를 사용해야 합니다.lang.reflect 패키지의 Proxy 클래스, 이 클래스는 하나의 인터페이스, 하나의 클래스 마운트와 Impatient Proxy 실례 대상이 필요하기 때문에 우리는 에이전트 클래스에 다음과 같은 방법을 추가할 수 있습니다. 이 newInstance의 정적 방법은 우리에게 정적 에이전트 대상을 만들어 줍니다. 이 방법이 되돌아오는 대상은 포장된 대상의 모든 인터페이스를 실현하고 임의의 유형의 대상으로 전환할 수 있습니다.
package xidian.lili.edu.proxy;

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

public class ImpatientProxy implements InvocationHandler{
	private Object obj;
	public ImpatientProxy(Object obj){
		this.obj=obj;
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object result;
		long t1=System.currentTimeMillis();
		result=method.invoke(obj, args);
		long t2=System.currentTimeMillis();
		System.out.println("It takes "+(t2-t1)+" millis to invoke "+method.getName());
		return result;
	}
	public static Object newInstance(Object obj){
		ClassLoader loader=obj.getClass().getClassLoader();
		Class[] classes=obj.getClass().getInterfaces();
		return Proxy.newProxyInstance(loader, classes, new ImpatientProxy(obj));
	}
}

동적 에이전트를 썼을 때, 예를 들어, 대상이 차단하고 싶은 방법에 속하는 인터페이스를 실현하면, 에이전트를 사용하여 대상을 포장할 수 있다.
package xidian.lili.edu.proxy;

import java.util.HashSet;
import java.util.Set;

public class ShowDynamicProxy {

	public static void main(String[] args) {
		Set s=new HashSet();
		//       s  
		s=(Set) ImpatientProxy.newInstance(s);
		s.add("hello world");
		s.isEmpty();
	}

}

방법의 실행 전후에 호출을 차단하고 슬라이드 프로그래밍 (AOP) 에 대한 자신의 생각을 만듭니다.

실현 인터페이스 없음(cglib)


CGLIB는 기능이 강하고 고성능의 코드 생성 패키지이다.이것은 인터페이스를 실현하지 못한 클래스에 에이전트를 제공하고 JDK의 동적 에이전트에 좋은 보충을 제공한다.일반적으로 자바의 동적 에이전트를 사용하여 에이전트를 만들 수 있지만, 에이전트를 만들 클래스가 인터페이스를 실현하지 못하거나, 더 좋은 성능을 위해 CGLIB는 좋은 선택입니다.
GLib 베이스는 ASM 바이트 생성 프레임워크를 사용하고 바이트 기술로 프록시 클래스를 생성하여 자바를 사용하는 것보다 반사 효율이 높다.유일하게 주의해야 할 것은 CGLib이final로 성명하는 방법을 에이전트할 수 없다는 것이다. 왜냐하면 CGLib의 원리는 에이전트된 클래스의 하위 클래스를 동적으로 생성하는 것이기 때문이다.

좋은 웹페이지 즐겨찾기