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