淺析Java中的動(dòng)態(tài)代理
代理常見(jiàn)功能
日志代理
數(shù)據(jù)庫(kù)訪問(wèn)的事務(wù)代理
代理模式的組成
- 抽象主題:通過(guò)接口或抽象類定義核心業(yè)務(wù)方法。
- 真實(shí)主題:實(shí)現(xiàn)了接口的實(shí)現(xiàn)類,是實(shí)施代理的具體對(duì)象。即代理最終代理的是具體的實(shí)現(xiàn)類類而不是接口。
- 代理:具有與代理對(duì)象相同的方法,可以控制和擴(kuò)展被代理對(duì)象的功能,也是使用代理對(duì)象的根據(jù)目的。
代理對(duì)象 = 增強(qiáng)代碼 + 目標(biāo)對(duì)象(原對(duì)象)
代理模式分類
靜態(tài)代理:代理類與被代理類一一對(duì)應(yīng),缺點(diǎn)是代理類太多。
動(dòng)態(tài)代理:代理類是運(yùn)行時(shí)通過(guò)反射技術(shù)動(dòng)態(tài)生成的。有點(diǎn)是一類相似功能的被代理類(即需要相同擴(kuò)展功能的類)只需要一個(gè)動(dòng)態(tài)代理類。
動(dòng)態(tài)代理實(shí)現(xiàn)的技術(shù)
JDK 代理:面向接口的代理,無(wú)法直接代理類,被代理的類必須實(shí)現(xiàn)某業(yè)務(wù)接口。
CGLIB 代理:功能更強(qiáng),性能更好,可以直接代理類而不用實(shí)現(xiàn)接口,是通過(guò)動(dòng)態(tài)創(chuàng)建被代理的子類重寫(xiě)父類的被代理方法來(lái)實(shí)現(xiàn)統(tǒng)計(jì)附件功能的。不能代理final類或final方法。
JDK 代理的實(shí)現(xiàn)步驟
核心業(yè)務(wù)接口
public interface Buyer {
/**
* 賣(mài)房:核心業(yè)務(wù)方法
* @return
*/
String buy();
}
業(yè)務(wù)實(shí)現(xiàn)類
public class BuyerImpl implements Buyer{
public String buy() {
System.out.println("本人賣(mài)房,從不坑人...");
return "一次搞定";
}
}
動(dòng)態(tài)代理類
public class BuyerInvocationHandler implements InvocationHandler {
//被代理對(duì)象
private Object target;
/**
* 設(shè)置被代理對(duì)象
* @param target
*/
public void setTarget(Object target) {
this.target = target;
}
/**
* 執(zhí)行被代理對(duì)象的業(yè)務(wù)方法的代理方法
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("熬夜?jié)M大街收集電話號(hào)碼.....");
//調(diào)用核心業(yè)務(wù)方法
Object result = method.invoke(target,args);
System.out.println("不滿意,再找我...");
return result;
}
}
代理工廠類
public class BuyerProxyFactory {
/**
* 工廠方法
* @param target 需要被代理的對(duì)象
* @param <T>
* @return 返回動(dòng)態(tài)生成的代理對(duì)象
*/
public static <T> T create(Object target){
// 創(chuàng)建動(dòng)態(tài)代理對(duì)象
BuyerInvocationHandler handler = new BuyerInvocationHandler();
// 設(shè)置被代理對(duì)象
handler.setTarget(target);
// 動(dòng)態(tài)創(chuàng)建執(zhí)行業(yè)務(wù)方法的代理對(duì)象
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler);
}
}測(cè)試類
public class example {
public static void main(String[] args) {
//定義被代理對(duì)象
//定義被代理對(duì)象
Buyer buyer = new BuyerImpl();
buyer.buy(); // 直接調(diào)用業(yè)務(wù)方法,沒(méi)有代理的功能
// 使用代理工廠創(chuàng)建動(dòng)態(tài)代理類對(duì)象
Buyer proxyBuyer = BuyerProxyFactory.create(buyer);
proxyBuyer.buy();
}
}
CGLIB 代理實(shí)現(xiàn)步驟
導(dǎo)入 POM
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.3.0</version>
</dependency>
定義業(yè)務(wù)方法
public class OrderService {
public int insert(){
System.out.println("添加訂單....");
return 0;
}
}
定義代理工廠類,與提供事務(wù)控制功能的MethodInterceptor合二為一
public class TransactionProxyFactory {
/**
* 動(dòng)態(tài)創(chuàng)建被代理類的代理對(duì)象
* @param clazz 類型
* @param <T>
* @return 代理對(duì)象
*/
public static <T> T create(Class<T> clazz){
Enhancer enhancer = new Enhancer();
// 采用接口內(nèi)部類的方式實(shí)現(xiàn)代理功能
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object target, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("開(kāi)始事務(wù)。。。。");
// 核心業(yè)務(wù),調(diào)用父類的方法
Object result = methodProxy.invokeSuper(target,objects);
System.out.println("提交或回滾事務(wù)....");
return result;
}
});
// 設(shè)置代理類的父類
enhancer.setSuperclass(clazz);
// 返回創(chuàng)建的動(dòng)態(tài)代理類對(duì)象
return (T) enhancer.create();
}
}測(cè)試類
public class TransactionProxyFactoryTest {
public static void main(String[] args) {
// 使用代理創(chuàng)建業(yè)務(wù)邏輯類
OrderService orderService =
TransactionProxyFactory.create(OrderService.class);
orderService.insert();
CartService cartService = TransactionProxyFactory.create(CartService.class);
cartService.insert();
}
}
到此這篇關(guān)于淺析Java中的動(dòng)態(tài)代理的文章就介紹到這了,更多相關(guān)Java動(dòng)態(tài)代理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Security 自定義資源服務(wù)器實(shí)踐過(guò)程
這篇文章主要介紹了Spring Security 自定義資源服務(wù)器實(shí)踐,我們通過(guò)自己搭建的授權(quán)服務(wù)器和資源服務(wù)器,完整體驗(yàn)了OAuth2流程,需要的朋友可以參考下2022-08-08
Jenkins配置前端自動(dòng)打包部署全過(guò)程(若依項(xiàng)目)
Jenkins作為一個(gè)開(kāi)源的自動(dòng)化服務(wù)器,廣泛用于持續(xù)集成、持續(xù)部署(CI/CD)流程中,這篇文章主要給大家介紹了關(guān)于Jenkins配置前端自動(dòng)打包部署(若依項(xiàng)目)的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2024-09-09
如何將復(fù)雜SQL轉(zhuǎn)換成Java對(duì)象的實(shí)例講解
轉(zhuǎn)換復(fù)雜SQL到Java代碼,我們需要確定數(shù)據(jù)庫(kù)連接方式和工具,使用JDBC的API來(lái)連接數(shù)據(jù)庫(kù)、執(zhí)行SQL語(yǔ)句,復(fù)雜SQL語(yǔ)句可以被拆分為多個(gè)步驟,每個(gè)步驟執(zhí)行一個(gè)特定的操作,通過(guò)將SQL語(yǔ)句拆分為多個(gè)步驟,我們可以更好地理解復(fù)雜SQL的邏輯,并且更容易將其轉(zhuǎn)換為Java代碼2024-05-05
SpringCloud之消息總線Spring Cloud Bus實(shí)例代碼
這篇文章主要介紹了SpringCloud之消息總線Spring Cloud Bus實(shí)例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04
springboot整合JSR303校驗(yàn)功能實(shí)現(xiàn)代碼
這篇文章主要介紹了springboot整合JSR303校驗(yàn)功能實(shí)現(xiàn),JSR303校驗(yàn)方法有統(tǒng)一校驗(yàn)的需求,統(tǒng)一校驗(yàn)實(shí)現(xiàn)以及分組校驗(yàn),本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01
Mybatis-Plus同時(shí)使用邏輯刪除和唯一索引的問(wèn)題及解決辦法(報(bào)數(shù)據(jù)重復(fù)Duplicate entry的
在開(kāi)發(fā)中,我們經(jīng)常會(huì)有邏輯刪除和唯一索引同時(shí)使用的情況,但當(dāng)使用mybatis plus時(shí),如果同時(shí)使用邏輯刪除和唯一索引,會(huì)報(bào)數(shù)據(jù)重復(fù)Duplicate entry的問(wèn)題,如何解決這個(gè)問(wèn)題呢,小編給大家分享Mybatis-Plus同時(shí)使用邏輯刪除和唯一索引的問(wèn)題及解決辦法,一起看看吧2023-11-11

