日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Javal动态代理

發布時間:2024/4/13 java 66 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Javal动态代理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Proxy設計模式

代理模式為其他對象提供一個代理以控制對某個對象的訪問。

?

為了行為的一致性,代理類與委托類通常會實現相同的接口。

代理模式與適配器、裝飾者模式的區別:

代理模式與適配器、裝飾者模式,都包裝了一個內部對象,對請求進行,但是他們有本質的區別:

  • 裝飾者模式,擴展了包裝對象的行為和責任。包裝對象與被包裝對象實現了相同的接口,即有共同的行為。

  • 適配器模式,擴展了包裝對象的行為和責任。但是進行了接口轉換。

  • 代理模式,未擴展行為和責任,是控制對象的訪問。包裝對象與被包裝對象實現了相同的接口。

?

按照代理的創建時期,代理類可以分為兩種:?

靜態:由程序員創建代理類或特定工具自動生成源代碼再對其編譯。在程序運行前代理類的.class文件就已經存在了。

動態:在程序運行時運用反射機制動態創建而成

Java靜態代理

//real Subjectpublic class UserManagerImpl implements UserManager { @Override public void addUser(String userId, String userName) { System.out.println("UserManagerImpl.addUser"); } @Override public void delUser(String userId) { System.out.println("UserManagerImpl.delUser"); } @Override public String findUser(String userId) { System.out.println("UserManagerImpl.findUser"); return "張三"; } @Override public void modifyUser(String userId, String userName) { System.out.println("UserManagerImpl.modifyUser"); } } //Proxypublic class UserManagerImplProxy implements UserManager { // 目標對象 private UserManager userManager; // 通過構造方法傳入目標對象 public UserManagerImplProxy(UserManager userManager){ this.userManager=userManager; } @Override public void addUser(String userId, String userName) { try{ //添加打印日志的功能 //開始添加用戶 System.out.println("start-->addUser()"); userManager.addUser(userId, userName); //添加用戶成功 System.out.println("success-->addUser()"); }catch(Exception e){ //添加用戶失敗 System.out.println("error-->addUser()"); } } @Override public void delUser(String userId) { userManager.delUser(userId); } @Override public String findUser(String userId) { userManager.findUser(userId); return "張三"; } @Override public void modifyUser(String userId, String userName) { userManager.modifyUser(userId,userName); } } //Client 使用代理public class Client { public static void main(String[] args){ //UserManager userManager=new UserManagerImpl(); UserManager userManager=new UserManagerImplProxy(new UserManagerImpl()); userManager.addUser("1111", "張三"); } }

代理模式的缺點

  • 代理類與委托類實現了相同接口,接口修改會導致所有實現了接口的代理類修需要修改。
  • 代理類僅能服務于某個接口,如果多個接口實現需要代理功能,則必須為所有接口創建代理類。即靜態代理只能服務于某個特定接口。
  • JDK動態代理

    靜態代理一個代理只能代理一種類型,而且是在編譯器就已經確定被代理的對象。而動態代理是在運行時,通過反射機制實現動態代理,并且能夠代理各種類型的對象

    在Java中要想實現動態代理機制,需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 類的支持

    //Object proxy:被代理的對象 //Method method:要調用的方法 //Object[] args:方法調用時所需要參數 public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; } //java.lang.reflect.Proxy 類://CLassLoader loader:類的加載器 //Class<?> interfaces:得到全部的接口 //InvocationHandler h:得到InvocationHandler接口的子類的實例 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

    示例代碼:

    public interface UserManager {void addUser(String userId, String userName);void delUser(String userId);String findUser(String userId);void modifyUser(String userId, String userName);}public class UserManagerImpl implements UserManager {@Override public void addUser(String userId, String userName) { System.out.println("UserManagerImpl.addUser"); } @Override public void delUser(String userId) { System.out.println("UserManagerImpl.delUser"); } @Override public String findUser(String userId) { System.out.println("UserManagerImpl.findUser"); return "張三"; } @Override public void modifyUser(String userId, String userName) { System.out.println("UserManagerImpl.modifyUser"); } }import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method;public class LogHandler implements InvocationHandler{// 目標對象 private Object targetObject; //綁定關系,也就是關聯到哪個接口(與具體的實現類綁定)的哪些方法將被調用時,執行invoke方法。 public void setTarget(Object targetObject){ this.targetObject=targetObject; } @Override //關聯的這個實現類的方法被調用時將被執行 /*InvocationHandler接口的方法,proxy表示代理,method表示原對象被調用的方法,args表示方法的參數*/ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("start-->>"); for(int i=0;i<args.length;i++){ System.out.println(args[i]); } Object ret=null; try{ /*原對象方法調用前處理日志信息*/ System.out.println("satrt-->>"); //調用目標方法 ret=method.invoke(targetObject, args); /*原對象方法調用后處理日志信息*/ System.out.println("success-->>"); }catch(Exception e){ e.printStackTrace(); System.out.println("error-->>"); throw e; } return ret; } }public class UserManagerTest {public static void main(String[] args) {// TODO Auto-generated method stubUserManager userManager = new UserManagerImpl();LogHandler logHandler=new LogHandler(); logHandler.setTarget(userManager);//該方法用于為指定類裝載器、一組接口及調用處理器生成動態代理類實例 //根據傳入的目標返回一個代理對象 UserManager proxy =(UserManager) Proxy.newProxyInstance(//第一個參數指定產生代理對象的類加載器,需要將其指定為和目標對象同一個類加載器 userManager.getClass().getClassLoader() //第二個參數要實現和目標對象一樣的接口,所以只需要拿到目標對象的實現接口 ,userManager.getClass().getInterfaces()//第三個參數表明這些被攔截的方法在被攔截時需要執行哪個InvocationHandler的invoke方法 ,logHandler); proxy.addUser("1111", "張三"); }}

    ?cglib代理

    Java靜態代理與JDK動態代理要求目標對象實現了一個接口,如果目標對象沒有實現接口,則不可以使用動態代理。此時可以使用Cglib代理來創建一個代理對象。

    Cglib代理,也叫作子類代理,它是在內存中構建一個子類對象從而實現對目標對象功能的擴展.

    • JDK的動態代理有一個限制,就是使用動態代理的對象必須實現一個或多個接口,如果想代理沒有實現接口的類,就可以使用Cglib實現.
    • Cglib是一個強大的高性能的代碼生成包,它可以在運行期擴展java類與實現java接口.它廣泛的被許多AOP的框架使用,例如Spring AOP和synaop,為他們提供方法的interception(攔截)
    • Cglib包的底層是通過使用一個小而塊的字節碼處理框架ASM來轉換字節碼并生成新的類.不鼓勵直接使用ASM,因為它要求你必須對JVM內部結構包括class文件的格式和指令集都很熟悉.

    Cglib子類代理實現方法:
    1.需要引入cglib的jar文件,但是Spring的核心包中已經包括了Cglib功能,所以直接引入pring-core-3.2.5.jar即可.
    2.引入功能包后,就可以在內存中動態構建子類
    3.代理的類不能為final,否則報錯
    4.目標對象的方法如果為final/static,那么就不會被攔截,即不會執行目標對象額外的業務方法.

    ?

    ?

    代碼示例:


    目標對象類:UserDao.java

    /*** 目標對象,沒有實現任何接口*/ public class UserDao {public void save() {System.out.println("----已經保存數據!----");} }

    Cglib代理工廠:ProxyFactory.java

    /*** Cglib子類代理工廠* 對UserDao在內存中動態構建一個子類對象*/ public class ProxyFactory implements MethodInterceptor{//維護目標對象private Object target;public ProxyFactory(Object target) {this.target = target;}//給目標對象創建一個代理對象public Object getProxyInstance(){//1.工具類Enhancer en = new Enhancer();//2.設置父類en.setSuperclass(target.getClass());//3.設置回調函數en.setCallback(this);//4.創建子類(代理對象)return en.create();}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("開始事務...");//執行目標對象的方法Object returnValue = method.invoke(target, args);System.out.println("提交事務...");return returnValue;} }

    測試類:

    /*** 測試類*/ public class App {@Testpublic void test(){//目標對象UserDao target = new UserDao();//代理對象UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();//執行代理對象的方法proxy.save();} }

    在Spring的AOP編程中:
    如果加入容器的目標對象有實現接口,用JDK代理
    如果目標對象沒有實現接口,用Cglib代理

    ?

    ?

    總結

    以上是生活随笔為你收集整理的Javal动态代理的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。