天天看點

Java中的靜态代理和動态代理1.靜态代理2.動态代理

Java中使用代理的作用是對目标對象的增強,在實際中我們可以在執行目标方法前後進行一些必要的處理。

1.靜态代理

靜态代理比較容易了解,我們直接給出例子。比如我們的目标方法是request方法,但是我們希望在每次調用request方法前都進行處理,如列印日志,那麼久需要使用代理來處理。

接口

public interface Subject{
    public void request();
}
           

目标類 

class SubjectImpl implements Subject{
  public void request(){
      System.out.println("I am dealing the request.");
  }
}
           

靜态代理類

在靜态代理類中我們接受實際的目标對象,并且在目标方法前後可以進行處理。

class StaticProxy implements Subject{
	//實際目标對象
    private Subject subject;
    
    public StaticProxy(Subject subject){
        this.subject = subject;
    }
    
    public void request(){
        System.out.println("PreProcess");
        subject.request();
        System.out.println("PostProcess");
    }
}
           

測試方法

在我們調用p.request()方法的時候則會列印出目标方法前後的資訊

public class StaticProxyDemo {
    public static void main(String args[]){
    	//建立實際對象
        SubjectImpl subject = new SubjectImpl();
        
        //把實際對象封裝到代理對象中
        StaticProxy p = new StaticProxy(subject);
        p.request();
    }
}
           

總結:靜态代理的優缺點很明顯,優點是代碼簡單,缺點是當目标對象有多個方法時,我們要對每個方法都進行處理,是以會非常繁瑣。

2.動态代理

動态代理克服了靜态代理的缺點,在動态代理中,目标對象的方法每次被調用都進行動态攔截。

簡單解釋一下下面的圖:用戶端每次調用都是代理對象的方法,不可能直接調用目标對象的方法,所有的調用方法都會被攔截下來,轉發給代理處理器的invoke方法進行處理,在代理處理器的invoke方法中我們可以判定該方法是什麼方法,有什麼參數。最後再調用目标對象的真實方法來進行工作,真實方法執行結束以後,一路傳回執行結果。

Java中的靜态代理和動态代理1.靜态代理2.動态代理

下面舉例

接口和目标類與靜态代理的相同

接口

public interface Subject {
	public void request();

}
           

目标類

public class SubjectImpl implements Subject {

	@Override
	public void request() {
		System.out.println("I am dealing the request.");
	}
}
           

代理處理器 

/*
 * 代理處理器,實作了InvocationHandler接口
 * */
public class ProxyHandler implements InvocationHandler {
	//持有目标對象的句柄
	private Subject subject;
	
	public ProxyHandler(Subject subject){
		this.subject = subject;
	}

	/*
	 * invoke()方法
	 * 此方法在代理對象調用任何一個方法時都會被調用
	 * 
	 * 第一個參數:proxy 代理對象
	 * 第二個參數:method 反射裡面的Method類,檢視具體調用哪個方法
	 * 第三個參數:args 具體的形參
	 * */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		//輸出代理類的名字
		System.out.println(proxy.getClass().getName());//代理對象所屬的類是虛拟機自動生成的
		
		//定義預處理工作,當然也可以根據method的不同進行不同的預處理工作
		System.out.println("=========before========");
		//調用真實的目标對象來進行工作
		Object result = method.invoke(subject, args);
		System.out.println("=========before========");
		return result;//傳回結果
	}

}
           

測試類 

//動态代理模式
public class TestDynamicProxy {
	public static void main(String[] args) {
		//1.建立目标對象
		final Subject subject = new SubjectImpl();
		
		//2.建立代理處理器對象
		ProxyHandler proxyHandler = new ProxyHandler(subject);
		
		//3.動态生成代理對象
		Subject proxySubject = (Subject) Proxy.newProxyInstance(
				subject.getClass().getClassLoader(), //類加載器
				subject.getClass().getInterfaces(), //具體的接口
				proxyHandler);	//代理對象需要代理處理器對象,代理處理器重寫了invoke方法	

		//4.用戶端通過代理對象調用方法,本次調用将自動地被代理處理器的invoke方法接收
		proxySubject.request();
		
		System.out.println(proxySubject.getClass().getName());
	}

}
           

測試結果:

Java中的靜态代理和動态代理1.靜态代理2.動态代理

com.sun.proxy.$Proxy0是代理對象所屬的類,它是由虛拟機自動生成的。

對代理處理器 的了解:

代理處理器持有目标對象的句柄,并實作InvocationHandler接口

  • 主要是實作了invoke方法
  • 所有的代理對象方法調用,都會轉發到invoke方法來
  • invoke的形參method,就是指代理對象方法的調用
  • 在invoke内部,可以根據method,使用目标對象不同的方法來響應請求