好程式設計師Java學習路線之Spring框架之動態代理

好程式設計師IT發表於2019-07-18

好程式設計師 Java 學習路線之 Spring 框架之動態代理, 前言: 動態代理是一種常用的設計模式,廣泛應用於框架中, Spring 框架的 AOP 特性就是應用動態代理實現的,想要理解 AOP 的實現原理我們就必須先理解動態代理。

什麼是代理模式

代理模式 GOF23 設計模式之一, 代理模式中存在代理者和被代理者,代理者和被代理者都具有相同的功能,並且代理者執行功能時會附加一些額外的操作

如:手機工廠和代理商都具有賣東西的功能,手機代理商除了幫工廠賣手機外,還能在賣手機前打廣告推銷,賣手機後還可以進行售後服務。


代理模式的 優點 :

1 )符合開閉原則,不用修改被代理者任何的程式碼,就能擴充套件新的功能

2 )專案的擴充套件和維護比較方便

 

代理模式分為:靜態代理和動態代理

靜態代理

什麼是靜態代理

1 )代理者和被代理者都實現了相同的介面(或繼承相同的父類)

2 )代理者包含了一個被代理者的物件

3 )呼叫功能時,代理者會呼叫被代理者的功能,同時附加新的操作

  1. /**
  2. 賣手機
  3. */
  4. public interface SellMobilePhone {
  5. void sellMobilePhone();
  6. }
  7. /**
  8. 小米手機工廠
  9. */
  10. public class MiPhoneFactory implements SellMobilePhone{
  11. public void sellMobilePhone() {
  12. System.out.println(" 生產了小米 9 手機,賣出去!! ");
  13. }
  14. }
  15. /**
  16. 小米代理商
  17. */
  18. public class MiPhoneAgent implements SellMobilePhone {
  19. // 被代理者,工廠物件
  20. private SellMobilePhone factory;
  21. // 透過構造方法傳入被代理者
  22. public MiPhoneAgent(SellMobilePhone factory){
  23. this.factory = factory;
  24. }
  25. public void sellMobilePhone() {
  26. System.out.println(" 打廣告,做活動 ~~~~~~~~~~~~~~~~~");
  27. // 呼叫被代理者的方法
  28. factory.sellMobilePhone();
  29. System.out.println(" 做售後,做推銷 ~~~~~~~~~~~~~~~~~");
  30. }
  31. }
  32. public class TestStaticProxy {
  33. @Test
  34. public void testProxy(){
  35. // 建立被代理者
  36. SellMobilePhone factory = new MiPhoneFactory();
  37. factory.sellMobilePhone();
  38. System.out.println("---------------------------------------");
  39. // 建立代理者
  40. SellMobilePhone agent = new MiPhoneAgent(factory);
  41. // 呼叫賣手機
  42. agent.sellMobilePhone();
  43. }
  44. }

靜態代理的問題:

靜態代理只能適合一種業務,如果有新的業務,就必須建立新的介面和新的代理,如新增賣電腦的介面和電腦工廠,就要建立新的電腦代理類。

 

動態代理

動態代理的特點:

1)  在不修改原有類的基礎上,為原來類新增新的功能

2)  不需要依賴某個具體業務

動態代理分為:JDK 動態代理 CGLib 動態代理

區別是:

JDK 動態代理的 被代理者必須實現任意介面

CGLib 動態代理不用實現介面,是透過繼承實現的

JDK 動態代理

實現步驟:

1 )代理類需要實現 InvocationHandler 介面

2 )實現 invoke 方法

3 )透過 Proxy 類的 newProxyInstance 方法來建立代理物件

  1. /**
  2. 動態代理
  3. */
  4. public class SalesAgent implements InvocationHandler{
  5. // 被代理者物件
  6. private Object object;
  7. /**
  8. 建立代理物件
  9. * @param object  被代理者
  10. * @return  代理者
  11. */
  12. public Object createProxy(Object object){
  13. this.object = object;
  14. //Proxy.newProxyInstance 建立動態代理的物件,傳入被代理物件的類載入器,介面, InvocationHandler 物件
  15. return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
  16. }
  17. /**
  18. 呼叫被代理者方法,同時新增新功能
  19. */
  20. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  21. System.out.println(" 銷售之前,打廣告 ~~~~~~");
  22. // 呼叫被代理者的方法
  23. Object result = method.invoke(object,args);
  24. System.out.println(" 銷售之後,做售後 ~~~~~~");
  25. return result;
  26. }
  27. }
  28. public class TestInvocationHandler {
  29. @Test
  30. public void testInvocation(){
  31. // 建立動態代理物件
  32. SalesAgent agent = new SalesAgent();
  33. // 被代理物件
  34. SellMobilePhone sellMobilePhone = new MiPhoneFactory();
  35. // 建立代理物件
  36. SellMobilePhone phoneProxy = (SellMobilePhone) agent.createProxy(sellMobilePhone);
  37. phoneProxy.sellMobilePhone();
  38. }
  39. }

CGLib 動態代理

特點:透過繼承實現,被代理者必須能被繼承,透過被代理類建立子類,子類就是父類的代理。

  1. /**
  2. * CGLib 動態代理
  3. *
  4. */
  5. public class CGLibProxy implements MethodInterceptor {
  6. /**
  7. 返回代理物件
  8. * @param object  被代理物件
  9. * @return  代理物件
  10. */
  11. public Object createProxy(Object object){
  12. // 建立加強器
  13. Enhancer eh = new Enhancer();
  14. // 設定被代理物件的類為父類
  15. eh.setSuperclass(object.getClass());
  16. // 設定代理物件的回撥
  17. eh.setCallback(this);
  18. return eh.create();
  19. }
  20. public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
  21. System.out.println(" 售前 ~~~~~~CGLIB");
  22. // 呼叫父類物件的方法
  23. Object res = proxy.invokeSuper(obj, args);
  24. System.out.println(" 售後 ~~~~~~CGLIB");
  25. return res;
  26. }
  27. }

總結

代理模式分為靜態代理和動態代理,靜態代理只能代理某一種業務,動態代理可以代理各種業務而不用新增新的代理類,動態代理分為 JDK 動態代理和 CGLib 動態代理, JDK 動態代理類必須實現某個介面,如果沒有實現介面則可以使用 CGlib 實現。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913892/viewspace-2651031/,如需轉載,請註明出處,否則將追究法律責任。

相關文章