一、什么是代理
舉例說明:當我想買一臺電腦,國內太貴了。委托好友A在國外幫忙買。
這個情節中我要實現的動作和好友實現的動作一樣,都是買電腦。好友幫我完成了這個動作,這就是代理。
類A和類B都實現一個interface接口C,C規定了A和B要完成的動作。借助B類實現A類完成接口中的動作。
1.使用代理的場景?
(1)功能增強:B完成接口中的動作之余還做了別的事情
(2)控制訪問:B不讓A訪問到目標類,只有通過B這個媒介,A才能訪問
二、靜態代理
靜態代理就是:自己寫類實現代理。
思路:一個接口C,一個代理類B,一個被代理類A。兩個類都實現接口C,在B實現接口中的方法時調用A對象方法。
接口C:
public interface Singer {void singing();int dance();
}
被代理類A
public class Cai implements Singer {@Overridepublic void singing() {System.out.println("cai 唱歌");}@Overridepublic int dance() {System.out.println("tiaowu");return 0;}
}
?代理類A
public class Caidaili implements Singer{private Singer cai = new Cai();@Overridepublic void singing() {System.out.println("先收錢");cai.singing();}@Overridepublic int dance() {System.out.println("先收錢");cai.dance();return 0;}
}
測試
public class Main {public static void main(String[] args) {Singer singer = new Caidaili();singer.singing();singer.dance();}
}
?靜態代理的局限性:如果被代理類太多了,每個被代理類都要有一個代理。這樣寫的代理類就太多了。因此引入動態代理,動態決定被代理類。
三、動態代理
動態代理就是不需要自己寫代理類了,通過反射或者繼承實現。動態代理有兩種模式:
(1)jdk動態代理
通過反射類實現代理
核心代碼:
Proxy.newProxyInstance(被代理的類的類加載器,被代理類實現的接口,實現InvocationHandler的類對象)
返回:代理類對象
參數列表中:InvocationHandler接口(函數式接口)重寫了invoke方法,重寫代碼中的核心:
被代理對象.方法()method.invoke(接口對象,參數)? ? ? ? ? ? ? ? ? //表示調用這個接口中的方法
實例:
接口
public interface Singer {void dance();int singing();}
被代理類
public class Cai implements Singer {@Overridepublic void dance() {System.out.println("Cai 在跳舞");}@Overridepublic int singing() {System.out.println("Cai 在唱歌");return 0;}
}
jdk動態代理實現
public class Test1 {public static void main(String[] args) {Cai cai =new Cai();
// Ruler ruler = new Ruler(cai);//構建了 以原被代理類為基準的代理類的一個對象// o 已經等同于 Student s = new Student(); 這個s了Object o = Proxy.newProxyInstance(Cai.class.getClassLoader(), new Class[]{Singer.class}, (proxy, method, args1) -> {System.out.println(proxy.getClass().toString());System.out.println("先收錢");Object returnVal = method.invoke(cai, args1);System.out.println("asdfasdf");return returnVal;});System.err.println(o.getClass().toString());if(o instanceof Singer){Singer singer = (Singer)o;singer.dance();singer.singing();singer.toString();}}
}
(2)cglib動態代理
不寫接口,通過繼承關系重寫方法實現代理
示例:
被代理類:
public class Singer {public void dance(){System.out.println("tiaowu");}public int singing(){System.out.println("changge");return 100;}
}
代理類:
public class SingerSub extends Singer {@Overridepublic void dance() {System.out.println("shouqian");super.dance();}@Overridepublic int singing() {System.out.println("shouqian");return super.singing();}
}
測試:
public class Main {public static void main(String[] args) {Singer singer = new SingerSub();singer.singing();singer.dance();}
}