對動態代理模式的理解
阿新 • • 發佈:2018-12-23
直接上程式碼
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方法中呼叫的時候,就會自動載入重複的程式碼了
動態程式碼一定有介面,一定有介面實現類