1. 程式人生 > >對動態代理模式的理解

對動態代理模式的理解

直接上程式碼

Subject介面

package cn.lichenyang.dao;

public interface Subject {
	
	   public void rent();
	    
	   public void hello(String str);
}

RealSubject,需要實現Subjct,實現自己的功能

package cn.lichenyang.dao.impl;

import cn.lichenyang.dao.Subject;

public class RealSubject implements Subject{

	@Override
	public void rent() {
		System.out.println("rent");
	}

	@Override
	public void hello(String str) {
		System.out.println("hello:"+str);
	}

}

DynamicProxy類,需要實現InvocationHandler介面

package cn.lichenyang.proxy;

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

//實現了InvocationHandler介面需要實現invoke方法
public class DynamicProxy implements InvocationHandler {

    // 這個就是我們要代理的真實物件
    private Object subject;
    
    //    構造方法,給我們要代理的真實物件賦初值
    public DynamicProxy(Object subject)
    {
        this.subject = subject;
    }
	
    
    //arg0:      指代我們所代理的那個  真實物件,和上面的subject是一個東西,不要Object subject,會重名
    //method:  指代的是我們所要呼叫  真實物件的某個方法的Method物件
    //args:    指代的是呼叫         真實物件某個方法時接受的引數
	@Override
	public Object invoke(Object arg0, Method method, Object[] args) throws Throwable {
		//在代理真實物件前我們可以新增一些自己的操作
        System.out.println("before rent house");
        
        
        //因為Object是執行過程建立的,不是真實存在的,所以輸出會報錯
        //需要明白的是,subject和arg0是一個東西就行了
//        System.err.println("subject" + subject);
//        System.err.println("arg0"+arg0);
        
        System.err.println("Method:" + method);
        System.err.println("args:" + args);//可以args[0]來檢視具體的引數
        
        //當代理物件呼叫真實物件的方法時,其會自動的跳轉到代理物件關聯的handler物件的invoke方法來進行呼叫
        //invoke方法執行時需要知道方法所在的物件(例項),這個例項通過最上方的宣告得到(就相當於是那個類中的方法需要被代理)
        //subject是真是物件,args是真是物件中的介面的方法所需要的引數
        method.invoke(subject, args);
        
        //在代理真實物件後我們也可以新增一些自己的操作
        System.out.println("after rent house");
        
        /*
         * 解釋:這個返回值寫null就行了,對整個代理物件沒有影響
         */
        return null;
		
	}

}

測試類:

package cn.lichenyang.test;

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

import cn.lichenyang.dao.Subject;
import cn.lichenyang.dao.impl.RealSubject;
import cn.lichenyang.proxy.DynamicProxy;

public class Client {

	public static void main(String[] args) {
		
	//通過多型,建立一個我們要代理的真實物件
        Subject realSubject = new RealSubject();

        //我們要代理哪個真實物件,就將該物件傳進去,最後是通過該真實物件來呼叫其方法的
        InvocationHandler handler = new DynamicProxy(realSubject);

        /*
         * 通過Proxy的newProxyInstance方法來建立我們的代理物件,我們來看看其三個引數
         * 第一個引數 handler.getClass().getClassLoader() ,我們這裡使用handler這個類的ClassLoader物件來載入我們的代理物件
         * 第二個引數realSubject.getClass().getInterfaces(),我們這裡為代理物件提供的介面是真實物件所實行的介面,表示我要代理的是該真實物件,這樣我就能呼叫這組介面中的方法了
         * 第三個引數handler, 我們這裡將這個代理物件關聯到了上方的 InvocationHandler 這個物件上
         */
        Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
                .getClass().getInterfaces(), handler);
        
        //呼叫這個方法的時候,進入代理物件中的proxy方法
        subject.hello("world");    //使用這個方法,args有值(world),使用下面的就沒有值
//        subject.rent();
	}
}

動態代理和靜態代理的區別:動態代理不用自己寫代理類,靜態代理需要自己寫代理類

可以橫向抽取重複的程式碼,然後放到invoke方法中,在main方法中呼叫的時候,就會自動載入重複的程式碼了

動態程式碼一定有介面,一定有介面實現類