Spring細(xì)數(shù)兩種代理模式之靜態(tài)代理和動(dòng)態(tài)代理概念及使用
代理模式
在學(xué)習(xí) AOP 之前,我們先來(lái)了解下代理模式, 代理模式分為靜態(tài)代理以及動(dòng)態(tài)代理,屬于23中設(shè)計(jì)模式之一。 AOP 的底層機(jī)制就是動(dòng)態(tài)代理。

作用:
通過(guò)代理類(lèi)為原始類(lèi)增加額外的功能
1、靜態(tài)代理
1)案例展示
【1】定義一個(gè) Teacher 接口,接口中定義兩個(gè)方法:teachOnLine 和 teachOffLine。
package cn.gc.spring03.interfce;
public interface Teacher {
String teachOnLine(String course);
String teachOffLine(String course);
}
【2】定義一個(gè)實(shí)現(xiàn) Teacher 接口的 TeacherA 實(shí)現(xiàn)類(lèi),代碼如下:
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("開(kāi)始"+course+"課程線上教學(xué)");
return course+"課程線上教學(xué)";
}
@Override
public String teachOffLine(String course) {
System.out.println("開(kāi)始"+course+"課程線下教學(xué)");
return course+"課程線下教學(xué)";
}
}
【3】現(xiàn)在我們要在兩個(gè)方法中的 開(kāi)始課程教學(xué) 的前后添加上下課鈴聲的功能,此時(shí)我們?cè)俣x一個(gè)實(shí)現(xiàn) Teacher 接口的靜態(tài)代理類(lè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+"課程上課時(shí)間到了");
String s = teacherA.teachOnLine(course);
System.out.println(course+"課程下課時(shí)間到了");
return s;
}
@Override
public String teachOffLine(String course) {
System.out.println(course+"課程上課時(shí)間到了");
String s = teacherA.teachOffLine(course);
System.out.println(course+"課程下課時(shí)間到了");
return s;
}
}
【4】運(yùn)行效果如下

2)靜態(tài)代理優(yōu)缺點(diǎn)
(1)優(yōu)點(diǎn) :在不修改目標(biāo)對(duì)象的功能前提下,能通過(guò)代理對(duì)象對(duì)目標(biāo)功能擴(kuò)展;可以使得真實(shí)角色更加純粹,不再去關(guān)注一些公共的事情;公共的業(yè)務(wù)由代理來(lái)完成,實(shí)現(xiàn)了業(yè)務(wù)的分工。
(2)缺點(diǎn) :因?yàn)榇韺?duì)象需要與目標(biāo)對(duì)象實(shí)現(xiàn)一樣的接口,所以會(huì)很多代理類(lèi) ,一旦接口增加方法,目標(biāo)對(duì)象與代理對(duì)象都要維護(hù),工作量變大,開(kāi)發(fā)效率降低。
3)開(kāi)發(fā)代理對(duì)象的原則
- 代理對(duì)象和目標(biāo)對(duì)象實(shí)現(xiàn)相同的接口
- 代理對(duì)象依賴于目標(biāo)對(duì)象
2、動(dòng)態(tài)代理
在不改變?cè)瓉?lái)的代碼的情況下,實(shí)現(xiàn)了對(duì)原有功能的增強(qiáng),這是 AOP 中最核心的思想。
AOP:縱向開(kāi)發(fā),橫向開(kāi)發(fā)

1)簡(jiǎn)介
動(dòng)態(tài)代理的角色和靜態(tài)代理的一樣。但是動(dòng)態(tài)代理的代理類(lèi)是動(dòng)態(tài)生成的,而靜態(tài)代理的代理類(lèi)是提前寫(xiě)好的。
動(dòng)態(tài)代理分為兩類(lèi),一類(lèi)是基于接口動(dòng)態(tài)代理(JDK),一類(lèi)是基于類(lèi)的動(dòng)態(tài)代理(CGLib)。
2)基于接口動(dòng)態(tài)代理(JDK)
程序運(yùn)行的過(guò)程中,通過(guò) JDK 提供代理技術(shù)動(dòng)態(tài)的為某個(gè)類(lèi)產(chǎn)生動(dòng)態(tài)代理對(duì)象的過(guò)程。
開(kāi)發(fā)代理對(duì)象的原則:
- 代理對(duì)象,不需要實(shí)現(xiàn)接口,但是目標(biāo)對(duì)象要實(shí)現(xiàn)接口,否則不能用JDK動(dòng)態(tài)代理。
- 代理對(duì)象的生成,是利用JDK的API,動(dòng)態(tài)的在內(nèi)存中構(gòu)建代理對(duì)象。
- 動(dòng)態(tài)代理也叫做 :JDK代理、接口代理。
JDK 的動(dòng)態(tài)代理需要了解兩個(gè)類(lèi):
核心 : InvocationHandler (調(diào)用處理程序) 和 Proxy (代理)

實(shí)現(xiàn)步驟:在上面案例的基礎(chǔ)上實(shí)現(xiàn)。
創(chuàng)建一個(gè)基于 JDK 的代理工具類(lèi) DynamicProxy 類(lèi):
package cn.gc.spring03.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/*
* 基于JDK的代理工具類(lèi)
*/
public class DynamicProxy {
//被代理對(duì)象
private Object target;
public DynamicProxy(Object obj) {
this.target = obj;
}
//生成代理對(duì)象
public Object getProxy() {
//獲取類(lèi)加載器
ClassLoader classLoader = target.getClass().getClassLoader();
//獲取被代理對(duì)象實(shí)現(xiàn)的所有接口
Class<?>[] interfaces = target.getClass().getInterfaces();
//增強(qiáng)功能代碼編寫(xiě)的位置
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 增強(qiáng)的功能
System.out.println(args[0] + "課程上課時(shí)間到了");
// 通過(guò)反射執(zhí)行目標(biāo)方法
Object invoke = method.invoke(target, args);
// 增強(qiáng)的功能
System.out.println(args[0] + "課程下課時(shí)間到了");
return invoke;
}
};
Object o = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
return o;
}
}
測(cè)試:
@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++");
}
運(yùn)行效果:

3)基于類(lèi)的動(dòng)態(tài)代理(CGLib)
開(kāi)發(fā)代理對(duì)象的原則:
- 代理對(duì)象無(wú)需和原始類(lèi)對(duì)象實(shí)現(xiàn)相同的接口
- 代理對(duì)象和原始類(lèi)對(duì)象要存在父子類(lèi)關(guān)系
CGLib 的動(dòng)態(tài)代理需要了解兩個(gè)類(lèi):
- 核心 : Enhancer 和 MethodInterceptor
實(shí)現(xiàn)步驟
創(chuàng)建一個(gè) Aoo 類(lèi):
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)建一個(gè)基于 CGLib 的代理工具類(lèi) CglibProxy 類(lèi):
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è)置類(lèi)加載器
enhancer.setClassLoader(CglibProxy.class.getClassLoader());
//設(shè)置被代理對(duì)象
enhancer.setSuperclass(target.getClass());
//增強(qiáng)功能代碼編寫(xiě)的位置
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);
//代理對(duì)象
Object o = enhancer.create();
return o;
}
}
測(cè)試:
@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);
}
運(yùn)行效果:

4)動(dòng)態(tài)代理的優(yōu)勢(shì)
- 可以使得真實(shí)角色更加純粹,不再去關(guān)注一些公共的事情。
- 公共的業(yè)務(wù)由代理來(lái)完成,實(shí)現(xiàn)了業(yè)務(wù)的分工。
- 公共業(yè)務(wù)發(fā)生擴(kuò)展時(shí)變得更加集中和方便。
- 一個(gè)動(dòng)態(tài)代理,一般代理某一類(lèi)業(yè)務(wù)。
- 一個(gè)動(dòng)態(tài)代理可以代理多個(gè)類(lèi),代理的是接口。

到此這篇關(guān)于Spring細(xì)數(shù)兩種代理模式之靜態(tài)代理和動(dòng)態(tài)代理概念及使用的文章就介紹到這了,更多相關(guān)Spring靜態(tài)代理與動(dòng)態(tài)代理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java可變個(gè)數(shù)形參的方法實(shí)例代碼
這篇文章主要給大家介紹了關(guān)于Java可變個(gè)數(shù)形參的相關(guān)資料,文中通過(guò)圖文以及實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-02-02
springboot動(dòng)態(tài)調(diào)用實(shí)現(xiàn)類(lèi)方式
這篇文章主要介紹了springboot動(dòng)態(tài)調(diào)用實(shí)現(xiàn)類(lèi)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
淺談Arrays.asList() 和ArrayList類(lèi)型區(qū)別
下面小編就為大家?guī)?lái)一篇Arrays.asList() 和ArrayList類(lèi)型區(qū)別。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10
解決Eclipse配置Tomcat出現(xiàn)Cannot create a server using the selected
這篇文章主要介紹了解決Eclipse配置Tomcat出現(xiàn)Cannot create a server using the selected type錯(cuò)誤的相關(guān)資料,需要的朋友可以參考下2017-02-02
java使用BeanUtils.copyProperties方法對(duì)象復(fù)制同名字段類(lèi)型不同賦值為空問(wèn)題解決方案
這篇文章主要給大家介紹了關(guān)于java使用BeanUtils.copyProperties方法對(duì)象復(fù)制同名字段類(lèi)型不同賦值為空問(wèn)題的解決方案,文中通過(guò)代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-11-11
解決Eclipse的Servers視圖中無(wú)法添加Tomcat6/Tomcat7的方法
這篇文章主要介紹了解決Eclipse的Servers視圖中無(wú)法添加Tomcat6/Tomcat7的方法的相關(guān)資料,需要的朋友可以參考下2017-02-02
SpringBoot自定義注解解決公共字段填充問(wèn)題解決
修改時(shí)間,修改人等字段時(shí),這些字段屬于公共字段,本文主要介紹了SpringBoot自定義注解解決公共字段填充問(wèn)題解決,使用它的好處就是可以統(tǒng)一對(duì)這些字段進(jìn)行處理,感興趣的可以了解一下2024-07-07
MyBatis-Plus中公共字段的統(tǒng)一處理的實(shí)現(xiàn)
在開(kāi)發(fā)中經(jīng)常遇到多個(gè)實(shí)體類(lèi)有共同的屬性字段,這些字段屬于公共字段,本文主要介紹了MyBatis-Plus中公共字段的統(tǒng)一處理的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2023-08-08

