Spring細數(shù)兩種代理模式之靜態(tài)代理和動態(tài)代理概念及使用
代理模式
在學習 AOP 之前,我們先來了解下代理模式, 代理模式分為靜態(tài)代理以及動態(tài)代理,屬于23中設(shè)計模式之一。 AOP 的底層機制就是動態(tài)代理。
作用:
通過代理類為原始類增加額外的功能
1、靜態(tài)代理
1)案例展示
【1】定義一個 Teacher 接口,接口中定義兩個方法:teachOnLine 和 teachOffLine。
package cn.gc.spring03.interfce; public interface Teacher { String teachOnLine(String course); String teachOffLine(String course); }
【2】定義一個實現(xiàn) Teacher 接口的 TeacherA 實現(xiàn)類,代碼如下:
package cn.gc.spring03.interfce.impl; import cn.gc.spring03.interfce.Teacher; public class TeacherA implements Teacher { @Override public String teachOnLine(String course) { System.out.println("開始"+course+"課程線上教學"); return course+"課程線上教學"; } @Override public String teachOffLine(String course) { System.out.println("開始"+course+"課程線下教學"); return course+"課程線下教學"; } }
【3】現(xiàn)在我們要在兩個方法中的 開始課程教學 的前后添加上下課鈴聲的功能,此時我們再定義一個實現(xiàn) Teacher 接口的靜態(tài)代理類 TeacherAStaticProxy,代碼如下:
package cn.gc.spring03.proxy; import cn.gc.spring03.interfce.Teacher; import cn.gc.spring03.interfce.impl.TeacherA; public class TeacherAStaticProxy implements Teacher { TeacherA teacherA=new TeacherA(); @Override public String teachOnLine(String course) { System.out.println(course+"課程上課時間到了"); String s = teacherA.teachOnLine(course); System.out.println(course+"課程下課時間到了"); return s; } @Override public String teachOffLine(String course) { System.out.println(course+"課程上課時間到了"); String s = teacherA.teachOffLine(course); System.out.println(course+"課程下課時間到了"); return s; } }
【4】運行效果如下
2)靜態(tài)代理優(yōu)缺點
(1)優(yōu)點 :在不修改目標對象的功能前提下,能通過代理對象對目標功能擴展;可以使得真實角色更加純粹,不再去關(guān)注一些公共的事情;公共的業(yè)務(wù)由代理來完成,實現(xiàn)了業(yè)務(wù)的分工。
(2)缺點 :因為代理對象需要與目標對象實現(xiàn)一樣的接口,所以會很多代理類 ,一旦接口增加方法,目標對象與代理對象都要維護,工作量變大,開發(fā)效率降低。
3)開發(fā)代理對象的原則
- 代理對象和目標對象實現(xiàn)相同的接口
- 代理對象依賴于目標對象
2、動態(tài)代理
在不改變原來的代碼的情況下,實現(xiàn)了對原有功能的增強,這是 AOP 中最核心的思想。
AOP:縱向開發(fā),橫向開發(fā)
1)簡介
動態(tài)代理的角色和靜態(tài)代理的一樣。但是動態(tài)代理的代理類是動態(tài)生成的,而靜態(tài)代理的代理類是提前寫好的。
動態(tài)代理分為兩類,一類是基于接口動態(tài)代理(JDK),一類是基于類的動態(tài)代理(CGLib)。
2)基于接口動態(tài)代理(JDK)
程序運行的過程中,通過 JDK 提供代理技術(shù)動態(tài)的為某個類產(chǎn)生動態(tài)代理對象的過程。
開發(fā)代理對象的原則:
- 代理對象,不需要實現(xiàn)接口,但是目標對象要實現(xiàn)接口,否則不能用JDK動態(tài)代理。
- 代理對象的生成,是利用JDK的API,動態(tài)的在內(nèi)存中構(gòu)建代理對象。
- 動態(tài)代理也叫做 :JDK代理、接口代理。
JDK 的動態(tài)代理需要了解兩個類:
核心 : InvocationHandler (調(diào)用處理程序) 和 Proxy (代理)
實現(xiàn)步驟:在上面案例的基礎(chǔ)上實現(xiàn)。
創(chuàng)建一個基于 JDK 的代理工具類 DynamicProxy 類:
package cn.gc.spring03.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /* * 基于JDK的代理工具類 */ public class DynamicProxy { //被代理對象 private Object target; public DynamicProxy(Object obj) { this.target = obj; } //生成代理對象 public Object getProxy() { //獲取類加載器 ClassLoader classLoader = target.getClass().getClassLoader(); //獲取被代理對象實現(xiàn)的所有接口 Class<?>[] interfaces = target.getClass().getInterfaces(); //增強功能代碼編寫的位置 InvocationHandler invocationHandler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 增強的功能 System.out.println(args[0] + "課程上課時間到了"); // 通過反射執(zhí)行目標方法 Object invoke = method.invoke(target, args); // 增強的功能 System.out.println(args[0] + "課程下課時間到了"); return invoke; } }; Object o = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler); return o; } }
測試:
@Test public void test02() { Teacher teacher = new TeacherA(); DynamicProxy dynamicProxy = new DynamicProxy(teacher); Teacher teacherProxy = (Teacher) dynamicProxy.getProxy(); teacherProxy.teachOnLine("Java"); System.out.println("______________________"); teacherProxy.teachOnLine("C++"); }
運行效果:
3)基于類的動態(tài)代理(CGLib)
開發(fā)代理對象的原則:
- 代理對象無需和原始類對象實現(xiàn)相同的接口
- 代理對象和原始類對象要存在父子類關(guān)系
CGLib 的動態(tài)代理需要了解兩個類:
- 核心 : Enhancer 和 MethodInterceptor
實現(xiàn)步驟
創(chuàng)建一個 Aoo 類:
package cn.gc.spring03.interfce.impl; public class Aoo { public String test01(String info){ System.out.println("Aoo中的test01方法被調(diào)用。"); return info; } }
創(chuàng)建一個基于 CGLib 的代理工具類 CglibProxy 類:
package cn.gc.spring03.proxy; import org.springframework.cglib.proxy.Callback; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CglibProxy { private Object target; public CglibProxy(Object obj){ this.target=obj; } public Object getProxy(){ Enhancer enhancer=new Enhancer(); //設(shè)置類加載器 enhancer.setClassLoader(CglibProxy.class.getClassLoader()); //設(shè)置被代理對象 enhancer.setSuperclass(target.getClass()); //增強功能代碼編寫的位置 MethodInterceptor methodInterceptor=new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("-------------cglib log--------------"); Object invoke = method.invoke(target, objects); System.out.println("-------------cglib log--------------"); return invoke; } }; enhancer.setCallback(methodInterceptor); //代理對象 Object o = enhancer.create(); return o; } }
測試:
@Test public void test03() { Aoo aoo=new Aoo(); CglibProxy cglibProxy = new CglibProxy(aoo); Aoo proxy = (Aoo) cglibProxy.getProxy(); String info = proxy.test01("java"); System.out.println("info = " + info); }
運行效果:
4)動態(tài)代理的優(yōu)勢
- 可以使得真實角色更加純粹,不再去關(guān)注一些公共的事情。
- 公共的業(yè)務(wù)由代理來完成,實現(xiàn)了業(yè)務(wù)的分工。
- 公共業(yè)務(wù)發(fā)生擴展時變得更加集中和方便。
- 一個動態(tài)代理,一般代理某一類業(yè)務(wù)。
- 一個動態(tài)代理可以代理多個類,代理的是接口。
到此這篇關(guān)于Spring細數(shù)兩種代理模式之靜態(tài)代理和動態(tài)代理概念及使用的文章就介紹到這了,更多相關(guān)Spring靜態(tài)代理與動態(tài)代理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決IDEA中 Ctrl+ALT+V這個快捷鍵無法使用的情況
這篇文章主要介紹了解決IDEA中 Ctrl+ALT+V這個快捷鍵無法使用的情況,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02Java應(yīng)用服務(wù)器之tomcat會話復制集群配置的示例詳解
這篇文章主要介紹了Java應(yīng)用服務(wù)器之tomcat會話復制集群配置的相關(guān)知識,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07Java?IO模型之BIO、NIO、AIO三種常見IO模型解析
這篇文章主要介紹了今天我們來聊Java?IO模型,BIO、NIO、AIO三種常見IO模型,我們從應(yīng)用調(diào)用的過程中來分析一下整個IO的執(zhí)行過程,不過在此之前,我們需要簡單的了解一下整個操作系統(tǒng)的空間布局,需要的朋友可以參考下2024-07-07SpringBoot中如何解決讀取properties文件讀取問題
這篇文章主要介紹了SpringBoot中如何解決讀取properties文件讀取問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07使用java實現(xiàn)各種數(shù)據(jù)統(tǒng)計圖(柱形圖,餅圖,折線圖)
用Jfree實現(xiàn)條形柱狀圖表,java代碼實現(xiàn)??山?jīng)常用于報表的制作,代碼自動生成后可以自由查看。可以自由配置圖表的各個屬性,用來達到自己的要求和目的。本文給大家介紹使用java實現(xiàn)各種數(shù)據(jù)統(tǒng)計圖(柱形圖,餅圖,折線圖),需要的朋友可以參考下2015-10-10springboot訪問template下的html頁面的實現(xiàn)配置
這篇文章主要介紹了springboot訪問template下的html頁面的實現(xiàn)配置,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-12-12詳解Elasticsearch如何把一個索引變?yōu)橹蛔x
這篇文章主要為大家介紹了詳解Elasticsearch如何把一個索引變?yōu)橹蛔x示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-02-02