java代理模式有靜態代理和動態代理兩種實現方式
一、靜態代理
代理模式可以在不修改被代理對象的基礎上,通過擴展代理類,進行一些功能的附加與增強。代理類和被代理類應該共同實現一個接口,或者是共同繼承某個類。
優點:
可以在不修改目標對象的前提下擴展目標對象的功能。
缺點:
冗餘:由於代理對象要實現與目標對象一致的接口,會產生過多的代理類。
不易維護:一旦接口增加方法,目標對象與代理對象都要進行修改。
**靜態代理的特點**
1、目標角色固定
2、在應用程序執行前就得到目標角色
3、代理對象會增強目標對象的行爲
4、有可能存在多個代理 引起"類爆炸"(缺點)
二、動態代理
動態代理利用了 JDK API,動態地在內存中構建代理對象,從而實現對目標對象的代理功能。
動態代理又被稱爲 JDK 代理或接口代理。靜態代理與動態代理的區別主要在:
1、靜態代理在編譯時就已經實現,編譯完成後代理類是一個實際的 class 文件
2、動態代理是在運行時動態生成的,即編譯完成後沒有實際的 class 文件,而是在運行時動態生成類字節碼,並加載到 JVM 中
注意:動態代理對象不需要實現接口,但是要求目標對象必須實現接口,否則不能使用動態代理。
JDK 中生成代理對象主要涉及兩個類,第一個類爲 java.lang.reflect.Proxy,通過靜態方法 newProxyInstance 生成代理對象,第二個爲 java.lang.reflect.InvocationHandler 接口,通過 invoke 方法對業務進行增強
**動態代理的特點**
1、目標對象不固定
2、在應用程序執行時動態創建目標對象
3、代理對象會增強目標對象的行爲
三、代碼實例
1、創建一個person接口,這個接口就是租客和中介的公共接口,這個接口有一個rentHouse()方法。
public interface Person { //租房 public void rentHouse(); }
2、創建租客Renter類,實現上述接口
public class Renter implements Person{ @Override public void rentHouse() { System.out.println("租客租房成功!"); } }
3、靜態代理
1)創建中介類RenterProxy,同樣實現Person接口,但是還另外持有一個租客類對象public class RenterProxy implements Person{ private Person renter; public RenterProxy(Person renter){ this.renter = renter; } @Override public void rentHouse() { System.out.println("中介找房東租房,轉租給租客!"); renter.rentHouse(); System.out.println("中介給租客鑰匙,租客入住!"); } }
2)測試
public class StaticProxyTest { public static void main(String[] args) { Person renter = new Renter(); RenterProxy proxy = new RenterProxy(renter); proxy.rentHouse(); } }
運行結果:
中介找房東租房,轉租給租客!
租客租房成功!
中介給租客鑰匙,租客入住!
4、動態代理
1)創建RenterInvocationHandler類,這個類實現了InvocationHandler接口,並持有一個被代理類的對象,InvocationHandler中有一個invoke方法,所有執行代理對象的方法都會被替換成執行invoke方法。然後通過反射在invoke方法中執行代理類的方法。在代理過程中,在執行代理類的方法前或者後可以執行自己的操作,這就是spring aop的主要原理。
public class RenterInvocationHandler<T> implements InvocationHandler{ //被代理類的對象 private T target; public RenterInvocationHandler(T target){ this.target = target; } /** * proxy:代表動態代理對象 * method:代表正在執行的方法 * args:代表調用目標方法時傳入的實參 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //代理過程中插入其他操作 System.out.println("租客和中介交流"); Object result = method.invoke(target, args); return result; } }
2)測試
public class ProxyTest { public static void main(String[] args) { //創建被代理的實例對象 Person renter = new Renter(); //創建InvocationHandler對象 InvocationHandler renterHandler = new RenterInvocationHandler<Person>(renter); //創建代理對象,代理對象的每個執行方法都會替換執行Invocation中的invoke方法 Person renterProxy = (Person)Proxy.newProxyInstance(Person.class.getClassLoader(),new Class<?>[]{Person.class}, renterHandler); renterProxy.rentHouse(); //也可以使用下面的方式創建代理類對象,Proxy.newProxyInstance其實就是對下面代碼的封裝 /*try { //使用Proxy類的getProxyClass靜態方法生成一個動態代理類renterProxy Class<?> renterProxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), new Class<?>[]{Person.class}); //獲取代理類renterProxy的構造器,參數爲InvocationHandler Constructor<?> constructor = renterProxyClass.getConstructor(InvocationHandler.class); //使用構造器創建一個代理類實例對象 Person renterProxy = (Person)constructor.newInstance(renterHandler); renterProxy.rentHouse(); // } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }*/ } }
執行結果:
租客和中介交流
租客租房成功!
參考:
https://blog.csdn.net/zjshuster/article/details/126439883
https://blog.csdn.net/qq_34609889/article/details/85317582
https://blog.csdn.net/longzorg_cn/article/details/129115728
https://blog.csdn.net/m0_67499084/article/details/124810718
一個person接口,這個接口就是租客和中介的公共接口,這個接口有一個rentHouse()方法