Spring JDK動(dòng)態(tài)代理實(shí)現(xiàn)過(guò)程詳解
這篇文章主要介紹了Spring JDK動(dòng)態(tài)代理實(shí)現(xiàn)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
1. 創(chuàng)建項(xiàng)目
在 MyEclipse 中創(chuàng)建一個(gè)名稱(chēng)為 springDemo03 的 Web 項(xiàng)目,將 Spring 支持和依賴(lài)的 JAR 包復(fù)制到 Web 項(xiàng)目的 WEB-INF/lib 目錄中,并發(fā)布到類(lèi)路徑下。
2. 創(chuàng)建接口 CustomerDao
在項(xiàng)目的 src 目錄下創(chuàng)建一個(gè)名為 com.mengma.dao 的包,在該包下創(chuàng)建一個(gè) CustomerDao 接口,編輯后如下所示。
package com.mengma.dao; public interface CustomerDao { public void add(); // 添加 public void update(); // 修改 public void delete(); // 刪除 public void find(); // 查詢(xún) }
3. 創(chuàng)建實(shí)現(xiàn)類(lèi) CustomerDaoImpl
在 com.mengma.dao 包下創(chuàng)建 CustomerDao 接口的實(shí)現(xiàn)類(lèi) CustomerDaoImpl,并實(shí)現(xiàn)該接口中的所有方法,如下所示。
package com.mengma.dao; public class CustomerDaoImpl implements CustomerDao { @Override public void add() { System.out.println("添加客戶(hù)..."); } @Override public void update() { System.out.println("修改客戶(hù)..."); } @Override public void delete() { System.out.println("刪除客戶(hù)..."); } @Override public void find() { System.out.println("修改客戶(hù)..."); } }
4. 創(chuàng)建切面類(lèi) MyAspect
在 src 目錄下,創(chuàng)建一個(gè)名為 com.mengma.jdk 的包,在該包下創(chuàng)建一個(gè)切面類(lèi) MyAspect,編輯后如下所示。
package com.mengma.jdk; public class MyAspect { public void myBefore() { System.out.println("方法執(zhí)行之前"); } public void myAfter() { System.out.println("方法執(zhí)行之后"); } }
上述代碼中,在切面中定義了兩個(gè)增強(qiáng)的方法,分別為 myBefore() 方法和 myAfter() 方法,用于對(duì)目標(biāo)類(lèi)(CustomerDaoImpl)進(jìn)行增強(qiáng)。
5. 創(chuàng)建代理類(lèi) MyBeanFactory
在 com.mengma.jdk 包下創(chuàng)建一個(gè)名為 MyBeanFactory 的類(lèi),在該類(lèi)中使用 java.lang.reflect.Proxy 實(shí)現(xiàn) JDK 動(dòng)態(tài)代理,如下所示。
package com.mengma.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import com.mengma.dao.CustomerDao; import com.mengma.dao.CustomerDaoImpl; public class MyBeanFactory { public static CustomerDao getBean() { // 準(zhǔn)備目標(biāo)類(lèi) final CustomerDao customerDao = new CustomerDaoImpl(); // 創(chuàng)建切面類(lèi)實(shí)例 final MyAspect myAspect = new MyAspect(); // 使用代理類(lèi),進(jìn)行增強(qiáng) return (CustomerDao) Proxy.newProxyInstance( MyBeanFactory.class.getClassLoader(), new Class[] { CustomerDao.class }, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { myAspect.myBefore(); // 前增強(qiáng) Object obj = method.invoke(customerDao, args); myAspect.myAfter(); // 后增強(qiáng) return obj; } }); } }
上述代碼中,定義了一個(gè)靜態(tài)的 getBean() 方法,這里模擬 Spring 框架的 IoC 思想,通過(guò)調(diào)用 getBean() 方法創(chuàng)建實(shí)例,第 14 行代碼創(chuàng)建了 customerDao 實(shí)例。
第 16 行代碼創(chuàng)建的切面類(lèi)實(shí)例用于調(diào)用切面類(lèi)中相應(yīng)的方法;第 18~26 行就是使用代理類(lèi)對(duì)創(chuàng)建的實(shí)例 customerDao 中的方法進(jìn)行增強(qiáng)的代碼,其中 Proxy 的 newProxyInstance() 方法的第一個(gè)參數(shù)是當(dāng)前類(lèi)的類(lèi)加載器,第二參數(shù)是所創(chuàng)建實(shí)例的實(shí)現(xiàn)類(lèi)的接口,第三個(gè)參數(shù)就是需要增強(qiáng)的方法。
在目標(biāo)類(lèi)方法執(zhí)行的前后,分別執(zhí)行切面類(lèi)中的 myBefore() 方法和 myAfter() 方法。
6. 創(chuàng)建測(cè)試類(lèi) JDKProxyTest
在 com.mengma.jdk 包下創(chuàng)建一個(gè)名為 JDKProxyTest 的測(cè)試類(lèi),如下所示。
package com.mengma.jdk; import org.junit.Test; import com.mengma.dao.CustomerDao; public class JDKProxyTest { @Test public void test() { // 從工廠(chǎng)獲得指定的內(nèi)容(相當(dāng)于spring獲得,但此內(nèi)容時(shí)代理對(duì)象) CustomerDao customerDao = MyBeanFactory.getBean(); // 執(zhí)行方法 customerDao.add(); customerDao.update(); customerDao.delete(); customerDao.find(); } }
上述代碼中,在調(diào)用 getBean() 方法時(shí),獲取的是 CustomerDao 類(lèi)的代理對(duì)象,然后調(diào)用了該對(duì)象中的方法。
7. 運(yùn)行項(xiàng)目并查看結(jié)果
使用 JUnit 測(cè)試運(yùn)行 test() 方法,運(yùn)行成功后,控制臺(tái)的輸出結(jié)果如圖 1 所示。
從下圖的輸出結(jié)果中可以看出,在調(diào)用目標(biāo)類(lèi)的方法前后,成功調(diào)用了增強(qiáng)的代碼,由此說(shuō)明,JDK 動(dòng)態(tài)代理已經(jīng)實(shí)現(xiàn)。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
@Controller、@RestController注解區(qū)別詳解
這篇文章主要介紹了@Controller、@RestController注解區(qū)別詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10Java實(shí)現(xiàn)鏈表中元素的獲取、查詢(xún)和修改方法詳解
這篇文章主要介紹了Java實(shí)現(xiàn)鏈表中元素的獲取、查詢(xún)和修改方法,結(jié)合實(shí)例形式詳細(xì)分析了Java針對(duì)鏈表中元素的獲取、查詢(xún)和修改相關(guān)原理、實(shí)現(xiàn)方法及操作注意事項(xiàng),需要的朋友可以參考下2020-03-03詳解使用SSM實(shí)現(xiàn)簡(jiǎn)單工作流系統(tǒng)之實(shí)現(xiàn)篇
這篇文章主要介紹了使用SSM實(shí)現(xiàn)簡(jiǎn)單工作流系統(tǒng)之實(shí)現(xiàn)篇,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12Java?@Scheduled定時(shí)任務(wù)不執(zhí)行解決辦法
這篇文章主要給大家介紹了關(guān)于Java?@Scheduled定時(shí)任務(wù)不執(zhí)行解決的相關(guān)資料,當(dāng)@Scheduled定時(shí)任務(wù)不執(zhí)行時(shí)可以根據(jù)以下步驟進(jìn)行排查和解決,需要的朋友可以參考下2023-10-10java?System類(lèi)和Arrays類(lèi)詳解
這篇文章主要介紹了java?System類(lèi)和Arrays類(lèi)詳解,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08Java8新特性stream和parallelStream區(qū)別
這篇文章主要介紹了Java8新特性stream和parallelStream區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11詳解SpringBoot集成Redis來(lái)實(shí)現(xiàn)緩存技術(shù)方案
本篇文章主要介紹了詳解SpringBoot集成Redis來(lái)實(shí)現(xiàn)緩存技術(shù)方案,具有一定的參考價(jià)值,有興趣的可以了解一下2017-06-06