更新時間:2021年05月25日16時56分 來源:傳智教育 瀏覽次數(shù):
JDK動態(tài)代理是通過java.lang.reflect.Proxy 類來實現(xiàn)的,我們可以調(diào)用Proxy類的newProxyInstance()方法來創(chuàng)建代理對象。對于使用業(yè)務接口的類,Spring默認會使用JDK動態(tài)代理來實現(xiàn)AOP。
接下來,通過一個案例來演示Spring中JDK動態(tài)代理的實現(xiàn)過程,具體步驟如下。
(1)創(chuàng)建一個名為chapter03的Web項目,導入Spring框架所需JAR包到項目的lib目錄中,并發(fā)布到類路徑下。
(2)在src目錄下,創(chuàng)建一個com.itheima.jdk包,在該包下創(chuàng)建接口UserDao,并在該接口中編寫添加和刪除的方法,如文件1所示。
文件1 UserDao.java
package com.itheima.jdk; public interface UserDao { public void addUser(); public void deleteUser(); }
(3)在com.itheima.jdk包中,創(chuàng)建UserDao接口的實現(xiàn)類UserDaoImpl,分別實現(xiàn)接口中的方法,并在每個方法中添加一條輸出語句,如文件2所示。
文件2 UserDaoImpl.java
package com.itheima.jdk; // 目標類 public class UserDaoImpl implements UserDao { public void addUser() { System.out.println("添加用戶"); } public void deleteUser() { System.out.println("刪除用戶"); } }
需要注意的是,本案例中會將實現(xiàn)類UserDaoImpl作為目標類,對其中的方法進行增強處理。
(4)在src目錄下,創(chuàng)建一個com.itheima.aspect包,并在該包下創(chuàng)建切面類MyAspect,在該類中定義一個模擬權(quán)限檢查的方法和一個模擬記錄日志的方法,這兩個方法就表示切面中的通知,如文件3所示。
文件3 MyAspect.java
package com.itheima.aspect; //切面類:可以存在多個通知Advice(即增強的方法) public class MyAspect { public void check_Permissions(){ System.out.println("模擬檢查權(quán)限..."); } public void log(){ System.out.println("模擬記錄日志..."); } }
(5)在com.itheima.jdk包下,創(chuàng)建代理類JdkProxy,該類需要實現(xiàn)InvocationHandler接口,并編寫代理方法。在代理方法中,需要通過Proxy類實現(xiàn)動態(tài)代理,如文件4所示。
文件4 JdkProxy.java
package com.itheima.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import com.itheima.aspect.MyAspect; /** * JDK代理類 */ public class JdkProxy implements InvocationHandler{ // 聲明目標類接口 private UserDao userDao; // 創(chuàng)建代理方法 public Object createProxy(UserDao userDao) { this.userDao = userDao; // 1.類加載器 ClassLoader classLoader = JdkProxy.class.getClassLoader(); // 2.被代理對象實現(xiàn)的所有接口 Class[] clazz = userDao.getClass().getInterfaces(); // 3.使用代理類,進行增強,返回的是代理后的對象 return Proxy.newProxyInstance(classLoader,clazz,this); } /* * 所有動態(tài)代理類的方法調(diào)用,都會交由invoke()方法去處理 * proxy 被代理后的對象 * method 將要被執(zhí)行的方法信息(反射) * args 執(zhí)行方法時需要的參數(shù) */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 聲明切面 MyAspect myAspect = new MyAspect(); // 前增強 myAspect.check_Permissions(); // 在目標類上調(diào)用方法,并傳入?yún)?shù) Object obj = method.invoke(userDao, args); // 后增強 myAspect.log(); return obj; } }
在文件4中,JdkProxy類實現(xiàn)了InvocationHandler接口,并實現(xiàn)了接口中的invoke()方法,所有動態(tài)代理類所調(diào)用的方法都會交由該方法處理。在創(chuàng)建的代理方法createProxy()中,使用了Proxy類的newProxyInstance()方法來創(chuàng)建代理對象。newProxyInstance()方法中包含三個參數(shù),其中第1個參數(shù)是當前類的類加載器,第2個參數(shù)表示的是被代理對象實現(xiàn)的所有接口,第3個參數(shù)this代表的就是代理類JdkProxy本身。在invoke()方法中,目標類方法執(zhí)行的前后,會分別執(zhí)行切面類中的check_Permissions()方法和log()方法。
(6)在com.itheima.jdk包中,創(chuàng)建測試類JdkTest。在該類中的main()方法中創(chuàng)建代理對象和目標對象,然后從代理對象中獲得對目標對象userDao增強后的對象,最后調(diào)用該對象中的添加和刪除方法,如文件5所示。
文件5 JdkTest.java
package com.itheima.jdk; public class JdkTest{ public static void main(String[] args) { // 創(chuàng)建代理對象 JdkProxy jdkProxy = new JdkProxy(); // 創(chuàng)建目標對象 UserDao userDao= new UserDaoImpl(); // 從代理對象中獲取增強后的目標對象 UserDao userDao1 = (UserDao) jdkProxy.createProxy(userDao); // 執(zhí)行方法 userDao1.addUser(); userDao1.deleteUser(); } }
執(zhí)行程序后,控制臺的輸出結(jié)果如圖1所示。
圖1 運行結(jié)果
從圖1可以看出,userDao實例中的添加用戶和刪除用戶的方法已被成功調(diào)用,并且在調(diào)用前后分別增加了檢查權(quán)限和記錄日志的功能。這種實現(xiàn)了接口的代理方式,就是Spring中的JDK動態(tài)代理。
猜你喜歡: