Java的代理模式之静态代理和动态代理
文章目錄
- 靜態(tài)代理
- 動(dòng)態(tài)代理
- jdk生成代理對(duì)象
- cglib代理
代理模式簡介:
代理(Proxy)是一種設(shè)計(jì)模式,提供了對(duì)目標(biāo)對(duì)象另外的訪問方式;即通過代理對(duì)象訪問目標(biāo)對(duì)象.這樣做的好處是:可以在目標(biāo)對(duì)象實(shí)現(xiàn)的基礎(chǔ)上,增強(qiáng)額外的功能操作,即擴(kuò)展目標(biāo)對(duì)象的功能.
這里使用到編程中的一個(gè)思想:不要隨意去修改別人已經(jīng)寫好的代碼或者方法,如果需改修改,可以通過代理的方式來擴(kuò)展該方法
舉例說明:我們買房子可以通過房產(chǎn)中介去購買,而不需要直接去找地產(chǎn)開發(fā)商去購買,其中中介就是我們的代理對(duì)象。
代理模式按類別可以分為三類:
- 靜態(tài)代理
- 動(dòng)態(tài)代理
動(dòng)態(tài)代理可以分為:jdk api動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理
靜態(tài)代理
靜態(tài)代理在使用時(shí),需要定義接口或者父類,被代理對(duì)象與代理對(duì)象一起實(shí)現(xiàn)相同的接口或者是繼承相同父類.
代碼示例:
代理接口UserDao
目標(biāo)對(duì)象UserDaoImpl
package com.sl.proxy;/*** @author shuliangzhao* @Title: UserDaoImpl* @ProjectName spring-boot-learn* @Description: TODO* @date 2019/10/19 17:02*/ public class UserDaoImpl implements UserDao {@Overridepublic void delete() {System.out.println("刪除數(shù)據(jù)");} }代理對(duì)象UserDaoProxy
package com.sl.proxy;/*** 代理對(duì)象* @author shuliangzhao* @Title: UserDaoProxy* @ProjectName spring-boot-learn* @Description: TODO* @date 2019/10/19 17:03*/ public class UserDaoProxy implements UserDao {private UserDao target;public UserDaoProxy(UserDao target) {this.target = target;}@Overridepublic void delete() {System.out.println("開始操作");target.delete();System.out.println("結(jié)束操作");} }測(cè)試類App
public class App {public static void main(String[] args) {UserDaoImpl userDao = new UserDaoImpl();UserDaoProxy userDaoProxy = new UserDaoProxy(userDao);userDaoProxy.delete();} }總結(jié):調(diào)用代理對(duì)象的方法來調(diào)用目標(biāo)對(duì)象.需要注意的是,代理對(duì)象與目標(biāo)對(duì)象要實(shí)現(xiàn)相同的接口,然后通過調(diào)用相同的方法來調(diào)用目標(biāo)對(duì)象的方法。
1.可以做到在不修改目標(biāo)對(duì)象的功能前提下,對(duì)目標(biāo)功能擴(kuò)展.
2.缺點(diǎn):因?yàn)榇韺?duì)象需要與目標(biāo)對(duì)象實(shí)現(xiàn)一樣的接口,所以會(huì)有很多代理類,類太多.同時(shí),一旦接口增加方法,目標(biāo)對(duì)象與代理對(duì)象都要維護(hù).
動(dòng)態(tài)代理
動(dòng)態(tài)代理特點(diǎn):
1、代理對(duì)象,不需要實(shí)現(xiàn)接口
2、代理對(duì)象的生成,是利用JDK的API,動(dòng)態(tài)的在內(nèi)存中構(gòu)建代理對(duì)象
jdk生成代理對(duì)象
JDK實(shí)現(xiàn)代理只需要使用Proxy.newProxyInstance方法,但是該方法需要接收三個(gè)參數(shù),完整的寫法是:
static Object newProxyInstance(ClassLoader loader, Class<?>[]
interfaces,InvocationHandler h )
- ClassLoader loader,:指定當(dāng)前目標(biāo)對(duì)象使用類加載器,獲取加載器的方法是固定的
- Class<?>[] interfaces,:目標(biāo)對(duì)象實(shí)現(xiàn)的接口的類型,使用泛型方式確認(rèn)類型
- InvocationHandler h:事件處理,執(zhí)行目標(biāo)對(duì)象的方法時(shí),會(huì)觸發(fā)事件處理器的方法,會(huì)把當(dāng)前執(zhí)行目標(biāo)對(duì)象的方法作為參數(shù)傳入
示例代碼
創(chuàng)建UserDaoInvocationHandler類,實(shí)現(xiàn)InvocationHandler接口,這個(gè)類中持有一個(gè)被代理對(duì)象的實(shí)例target
創(chuàng)建代理工廠類
package com.sl.jdkproxy;import java.lang.reflect.Proxy;/*** @author shuliangzhao* @Title: ProxyFactory* @ProjectName spring-boot-learn* @Description: TODO* @date 2019/10/19 17:19*/ public class ProxyFactory {//維護(hù)一個(gè)目標(biāo)對(duì)象private Object target;public ProxyFactory(Object target){this.target=target;}//給目標(biāo)對(duì)象生成代理對(duì)象public Object getProxyInstance() {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new UserDaoInvocationHandler(target));} }測(cè)試類App
package com.sl.jdkproxy;import com.sl.staticproxy.UserDao; import com.sl.staticproxy.UserDaoImpl;/*** @author shuliangzhao* @Title: App* @ProjectName spring-boot-learn* @Description: TODO* @date 2019/10/19 17:22*/ public class App {public static void main(String[] args) {UserDao userDao = new UserDaoImpl();UserDao proxyInstance = (UserDao) new ProxyFactory(userDao).getProxyInstance();System.out.println(proxyInstance.getClass());// 執(zhí)行方法 【代理對(duì)象】proxyInstance.delete();} }總結(jié):代理對(duì)象不需要實(shí)現(xiàn)接口,但是目標(biāo)對(duì)象一定要實(shí)現(xiàn)接口,否則不能用動(dòng)態(tài)代理
cglib代理
上面的靜態(tài)代理和動(dòng)態(tài)代理模式都是要求目標(biāo)對(duì)象是實(shí)現(xiàn)一個(gè)接口的目標(biāo)對(duì)象,但是有時(shí)候目標(biāo)對(duì)象只是一個(gè)單獨(dú)的對(duì)象,并沒有實(shí)現(xiàn)任何的接口,這個(gè)時(shí)候就可以使用以目標(biāo)對(duì)象子類的方式類實(shí)現(xiàn)代理,這種方法就叫做:Cglib代理
Cglib是一個(gè)強(qiáng)大的高性能的代碼生成包,它可以在運(yùn)行期擴(kuò)展java類與實(shí)現(xiàn)java接口.它廣泛的被許多AOP的框架使用,例如Spring AOP和synaop,為他們提供方法的interception(攔截)
使用cglib代理需要注意:
1.代理的類不能為final,否則報(bào)錯(cuò)
2.目標(biāo)對(duì)象的方法如果為final/static,那么就不會(huì)被攔截,即不會(huì)執(zhí)行目標(biāo)對(duì)象額外的業(yè)務(wù)方法.
示例代碼:
被代理的對(duì)象UserDao
創(chuàng)建代理工廠類
public class ProxyFactory implements MethodInterceptor {//維護(hù)目標(biāo)對(duì)象private Object target;public ProxyFactory(Object target) {this.target = target;}//給目標(biāo)對(duì)象創(chuàng)建一個(gè)代理對(duì)象public Object getProxyInstance() {//1.工具類Enhancer enhancer = new Enhancer();//2.設(shè)置父類enhancer.setSuperclass(target.getClass());//3.設(shè)置回調(diào)函數(shù)enhancer.setCallback(this);//4.創(chuàng)建子類return enhancer.create();}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("開始事務(wù)...");//執(zhí)行目標(biāo)對(duì)象的方法Object returnValue = method.invoke(target, objects);System.out.println("提交事務(wù)...");return returnValue;} }測(cè)試類
public class App {public static void main(String[] args) {UserDao userDao = new UserDao();UserDao proxyInstance = (UserDao) new ProxyFactory(userDao).getProxyInstance();proxyInstance.delete();} }總結(jié)
以上是生活随笔為你收集整理的Java的代理模式之静态代理和动态代理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringBoot @Value、 @
- 下一篇: Java GC日志查看和分析