摘要:代理模式的實(shí)現(xiàn)靜態(tài)代理優(yōu)缺點(diǎn)優(yōu)點(diǎn)只對(duì)對(duì)需要的方法加代理邏輯。通過(guò)繼承的方式進(jìn)行代理,無(wú)論目標(biāo)對(duì)象有沒(méi)有實(shí)現(xiàn)接口都可以代理,但是無(wú)法處理的情況。
注意:本文所有的class使用的static修飾主要是為了能在一個(gè)類里面測(cè)試。實(shí)際項(xiàng)目中不應(yīng)該這樣做的,應(yīng)該分包分class。
文字描述不是很多,還是看代碼比較好理解吧...
代理模式是一種設(shè)計(jì)模式,簡(jiǎn)單說(shuō)即是在不改變?cè)创a的情況下,實(shí)現(xiàn)對(duì)目標(biāo)對(duì)象的功能擴(kuò)展。
使用場(chǎng)景:如在方法執(zhí)行前后計(jì)算執(zhí)行時(shí)間,記錄日志等。在不改變?cè)a的條件下實(shí)現(xiàn)這些功能的擴(kuò)展。
優(yōu)點(diǎn): 只對(duì)對(duì)需要的方法加代理邏輯。
缺點(diǎn): 1.每次代理都需要實(shí)現(xiàn)一個(gè)代理類;2. 代理類功能固定,無(wú)法靈活改變。3. 項(xiàng)目會(huì)有一大批代理的代碼,如果目標(biāo)對(duì)象改變,代理類也需要對(duì)應(yīng)改變,不利于代碼的維護(hù)。
2.1.1 實(shí)現(xiàn)方式一:繼承代理(繼承方式實(shí)現(xiàn)代理)public class StaticProxyByExtendTest { //目標(biāo)對(duì)象 public static class UserServiceImpl { public void login(String username, String pwd) { System.out.println("Welcome " + username); } } //代理對(duì)象 public static class UserServiceImplProxy extends UserServiceImpl{ public void login(String username, String pwd) { System.out.println("before.... ");//代理額外邏輯 super.login(username, pwd);//調(diào)用原實(shí)現(xiàn)方法 System.out.println("after.... ");//代理額外邏輯 } } //測(cè)試 public static void main(String[] args) { UserServiceImpl ee = new UserServiceImplProxy(); ee.login("Stephen", "123"); } }2.1.2 實(shí)現(xiàn)方式二:聚合方式(通過(guò)實(shí)現(xiàn)相同接口)
public class StaticProxyByGroupTest { public interface UserService { public void login(String username, String pwd); } //目標(biāo)對(duì)象 public static class UserServiceImpl implements UserService { @Override public void login(String username, String pwd) { System.out.println("Welcome " + username); } } //代理對(duì)象 public static class UserServiceImplProxy implements UserService { private UserService userService; public UserServiceImplProxy(UserService userService) { this.userService = userService; } @Override public void login(String username, String pwd) { System.out.println("before.... ");//代理額外邏輯 userService.login(username, pwd);//調(diào)用原實(shí)現(xiàn)方法 System.out.println("after.... ");//代理額外邏輯 } } public static void main(String[] args) { UserService target = new UserServiceImpl(); UserService tt = new UserServiceImplProxy(target); tt.login("Stephen", "123"); } }
使用聚合方式我們還可以添加其他的代理對(duì)象來(lái)對(duì)已經(jīng)代理的對(duì)象繼續(xù)做增強(qiáng)代理。
2.2 動(dòng)態(tài)代理(JDK代理)JDK原生動(dòng)態(tài)代理是Java原生支持的,不需要任何外部依賴,但是它只能基于接口進(jìn)行代理;
2.2.0 優(yōu)缺點(diǎn)優(yōu)點(diǎn): 動(dòng)態(tài)代理所有接口。
缺點(diǎn): 必須依賴使用接口方式來(lái)實(shí)現(xiàn)代理。
主要實(shí)現(xiàn)是使用JDK自帶的Proxy類來(lái)實(shí)現(xiàn)
newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h)
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.
動(dòng)態(tài)代理不需要對(duì)方法逐一實(shí)現(xiàn)代理,通過(guò)反射循環(huán)所有的接口方法,統(tǒng)一動(dòng)態(tài)的加上代理邏輯。我們也可以通過(guò)執(zhí)行方法的名字來(lái)過(guò)濾當(dāng)前方法是否需要代理。
2.2.1 基本實(shí)現(xiàn)方式import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynamicProxyByJDKTest { public interface UserService { public void login(String username, String pwd); } //目標(biāo)對(duì)象 public static class UserServiceImpl implements UserService { @Override public void login(String username, String pwd) { System.out.println("Welcome " + username); } } //代理對(duì)象1 public static class UserServiceImplProxy { private UserService userServiceProxy; public UserServiceImplProxy(UserService userService) { //通過(guò)JDK動(dòng)態(tài)代理獲取UserService的代理對(duì)象 UserService proxy = (UserService) Proxy.newProxyInstance( userService.getClass().getClassLoader(), //1. 類加載器 userService.getClass().getInterfaces(), // 2. 代理需要實(shí)現(xiàn)的接口,可以有多個(gè) new InvocationHandler() { // 3. 方法調(diào)用的實(shí)際處理者 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before.... ");//代理額外邏輯 Object returnValue = method.invoke(userService, args); System.out.println("after.... ");//代理額外邏輯 return returnValue; } }); this.userServiceProxy = proxy; } public UserService getProxy() { return this.userServiceProxy; } } //獲取動(dòng)態(tài)代理對(duì)象的公共方法 @SuppressWarnings("unchecked") public static2.2.2 優(yōu)化動(dòng)態(tài)代理T getJDKProxy(T t) { T proxy = (T) Proxy.newProxyInstance( t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before.... ");//代理額外邏輯 Object returnValue = method.invoke(t, args); System.out.println("after.... ");//代理額外邏輯 return returnValue; } }); return proxy; } public static void main(String[] args) { UserService target = new UserServiceImpl(); //代理對(duì)象1 UserServiceImplProxy proxy = new UserServiceImplProxy(target); proxy.getProxy().login("Stephen", "123"); //代理對(duì)象 UserService jdkProxy = getJDKProxy(target); jdkProxy.login("JDK Stephen", "123"); } }
JDK Proxy動(dòng)態(tài)代理進(jìn)一步優(yōu)化:
抽象出代理父類
代理類實(shí)現(xiàn)自己的before和after方法
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynamicProxyByJDKTest2 { //目標(biāo)接口 public interface UserService { public void login(String username, String pwd); } //目標(biāo)對(duì)象 public static class UserServiceImpl implements UserService { @Override public void login(String username, String pwd) { System.out.println("Welcome " + username); } } //代理對(duì)象 public static class UserServiceImplProxy extends JDKProxy { public UserService userServiceProxy; public UserServiceImplProxy(UserService userService) { this.userServiceProxy = getJDKProxy(userService); } @Override protected void before(Method method) { System.out.println("before.... ");//代理額外邏輯 } @Override protected void after(Method method) { System.out.println("after.... ");//代理額外邏輯 } } //Common proxy object class public static abstract class JDKProxy { protected abstract void before(Method method); protected abstract void after(Method method); @SuppressWarnings("unchecked") protected2.3 Cglib代理T getJDKProxy(T t) { T proxy = (T) Proxy.newProxyInstance( t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(method);//代理額外邏輯 Object returnValue = method.invoke(t, args); after(method);//代理額外邏輯 return returnValue; } }); return proxy; } } public static void main(String[] args) { UserService target = new UserServiceImpl(); //代理對(duì)象 UserServiceImplProxy proxy = new UserServiceImplProxy(target); proxy.userServiceProxy.login("Stephen", "123"); } }
CGLIB(Code Generation Library)是一個(gè)基于ASM的字節(jié)碼生成庫(kù),它允許我們?cè)谶\(yùn)行時(shí)對(duì)字節(jié)碼進(jìn)行修改和動(dòng)態(tài)生成。
CGLIB通過(guò)繼承的方式進(jìn)行代理,無(wú)論目標(biāo)對(duì)象有沒(méi)有實(shí)現(xiàn)接口都可以代理,但是無(wú)法處理final的情況。
優(yōu)點(diǎn):Cglib代理不依賴接口,JDK代理賴接口
缺點(diǎn):
在Spring的AOP編程中:
如果加入容器的目標(biāo)對(duì)象有實(shí)現(xiàn)接口,用JDK代理
如果目標(biāo)對(duì)象沒(méi)有實(shí)現(xiàn)接口,用Cglib代理
2.3.1 使用spring-core實(shí)現(xiàn)cglib代理需要引用spring-core.jarSpring Core ? 5.1.8.RELEASE
import java.lang.reflect.Method; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; public class DynamicProxyBySpringCglibTest { //目標(biāo)接口 public interface UserService { public void login(String username, String pwd); } //目標(biāo)對(duì)象 public static class UserServiceImpl implements UserService { @Override public void login(String username, String pwd) { System.out.println("Welcome " + username); } } //代理對(duì)象 public static class ProxyFactory implements MethodInterceptor { private Object target; public ProxyFactory(Object target) { this.target = target; } public Object getProxyInstance(){ //1.工具類 Enhancer來(lái)指定要代理的目標(biāo)對(duì)象、實(shí)際處理代理邏輯的對(duì)象 Enhancer en = new Enhancer(); //2.設(shè)置父類 en.setSuperclass(target.getClass()); //3.設(shè)置回調(diào)函數(shù) en.setCallback(this); //4.創(chuàng)建子類(代理對(duì)象) return en.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("before.... ");//代理額外邏輯 Object returnValue = method.invoke(target, args); System.out.println("after.... ");//代理額外邏輯 return returnValue; } } public static void main(String[] args) throws Exception { UserService target = new UserServiceImpl(); UserService proxy = (UserService) new ProxyFactory(target).getProxyInstance(); proxy.login("Stephen", "123"); } }2.3.1 使用spring-core實(shí)現(xiàn)cglib代理(優(yōu)化版本)
主要優(yōu)化點(diǎn):
提取抽象公共的ProxyFactory類
具體代理類的實(shí)現(xiàn)繼承自ProxyFactory
import java.lang.reflect.Method; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; public class DynamicProxyBySpringCglibTest1 { //目標(biāo)接口 public interface UserService { public void login(String username, String pwd); } //目標(biāo)對(duì)象 public static class UserServiceImpl implements UserService { @Override public void login(String username, String pwd) { System.out.println("Welcome " + username); } } //Common代理對(duì)象 public static abstract class ProxyFactory implements MethodInterceptor { private Object target; public ProxyFactory(Object target) { this.target = target; } public Object getProxyInstance(){ //1.工具類 Enhancer en = new Enhancer(); //2.設(shè)置父類 en.setSuperclass(target.getClass()); //3.設(shè)置回調(diào)函數(shù) en.setCallback(this); //4.創(chuàng)建子類(代理對(duì)象) return en.create(); } protected abstract void before(Method method); protected abstract void after(Method method); @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { before(method); Object returnValue = method.invoke(target, args); after(method); return returnValue; } } //具體代理對(duì)象 public static class UserServiceProxy extends ProxyFactory { public UserServiceProxy(Object target) { super(target); } @Override protected void before(Method method) { System.out.println("before.... " + method.getName());//代理額外邏輯 } @Override protected void after(Method method) { System.out.println("after.... " + method.getName());//代理額外邏輯 } } public static void main(String[] args) throws Exception { UserService target = new UserServiceImpl(); UserService proxy = (UserService) new UserServiceProxy(target).getProxyInstance(); proxy.login("Stephen", "123"); } }3.Refs
API java.lang.reflect.Proxy
Spring Core ? 5.1.8.RELEASE
理解java的三種代理模式
java代理
Java代理和動(dòng)態(tài)代理機(jī)制分析和應(yīng)用
Java Proxy和CGLIB動(dòng)態(tài)代理原理
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/75438.html
摘要:函數(shù)式編程,一看這個(gè)詞,簡(jiǎn)直就是學(xué)院派的典范。所以這期周刊,我們就重點(diǎn)引入的函數(shù)式編程,淺入淺出,一窺函數(shù)式編程的思想,可能讓你對(duì)編程語(yǔ)言的理解更加融會(huì)貫通一些。但從根本上來(lái)說(shuō),函數(shù)式編程就是關(guān)于如使用通用的可復(fù)用函數(shù)進(jìn)行組合編程。 showImg(https://segmentfault.com/img/bVGQuc); 函數(shù)式編程(Functional Programming),一...
摘要:咱媽說(shuō)別亂點(diǎn)鏈接之淺談攻擊閱讀掘金作者馬達(dá)編輯迷鹿馬達(dá),精通開發(fā)開發(fā),擅長(zhǎng)接口設(shè)計(jì)以及平臺(tái)化建設(shè),獨(dú)自主導(dǎo)過(guò)多個(gè)產(chǎn)品。一題目購(gòu)物應(yīng)用分環(huán)境要求安全學(xué)習(xí)資料匯總掘金安全學(xué)習(xí)資料匯總安全學(xué)習(xí)網(wǎng)站收集 咱媽說(shuō)別亂點(diǎn)鏈接之淺談 CSRF 攻擊 - 閱讀 - 掘金作者 | 馬達(dá)編輯 | 迷鹿 馬達(dá), 精通PHP開發(fā)、Web開發(fā),擅長(zhǎng)api接口設(shè)計(jì)以及平臺(tái)化建設(shè),獨(dú)自主導(dǎo)過(guò)多個(gè)Web產(chǎn)品。目前就職...
摘要:咱媽說(shuō)別亂點(diǎn)鏈接之淺談攻擊閱讀掘金作者馬達(dá)編輯迷鹿馬達(dá),精通開發(fā)開發(fā),擅長(zhǎng)接口設(shè)計(jì)以及平臺(tái)化建設(shè),獨(dú)自主導(dǎo)過(guò)多個(gè)產(chǎn)品。一題目購(gòu)物應(yīng)用分環(huán)境要求安全學(xué)習(xí)資料匯總掘金安全學(xué)習(xí)資料匯總安全學(xué)習(xí)網(wǎng)站收集 咱媽說(shuō)別亂點(diǎn)鏈接之淺談 CSRF 攻擊 - 閱讀 - 掘金作者 | 馬達(dá)編輯 | 迷鹿 馬達(dá), 精通PHP開發(fā)、Web開發(fā),擅長(zhǎng)api接口設(shè)計(jì)以及平臺(tái)化建設(shè),獨(dú)自主導(dǎo)過(guò)多個(gè)Web產(chǎn)品。目前就職...
摘要:后文將圍繞做一些介紹。盡管如此,的使用對(duì)新手而言仍然充滿了困難。本系列文章基本為個(gè)人見解,難免有錯(cuò)誤與誤解,如有客觀錯(cuò)誤歡迎提出。 前言 說(shuō)到Android的污點(diǎn)分析框架,網(wǎng)上的搜索結(jié)果大多指向靜態(tài)的FlowDroid與動(dòng)態(tài)的TaintDroid。盡管由于加固、混淆等技術(shù)使得針對(duì)Android的靜態(tài)分析越來(lái)越困難,但靜態(tài)分析的無(wú)先驗(yàn)分析能力無(wú)法被動(dòng)態(tài)分析取代,使得靜態(tài)分析仍有發(fā)揮空間。...
閱讀 1398·2021-11-22 15:11
閱讀 2842·2019-08-30 14:16
閱讀 2760·2019-08-29 15:21
閱讀 2918·2019-08-29 15:11
閱讀 2459·2019-08-29 13:19
閱讀 2988·2019-08-29 12:25
閱讀 422·2019-08-29 12:21
閱讀 2836·2019-08-29 11:03