1. 程式人生 > >Java代理之靜態代理

Java代理之靜態代理

#### 什麼是代理 代理就是給目標物件一個代理物件,並由代理物件控制目標的引用。 #### 為什麼要使用代理模式 1、通過引入代理物件的方式,可以間接的訪問目標物件,避免直接訪問目標物件給系統帶來不必要的複雜性。 2、通過代理物件可以對原有的業務進行業務增強處理。 舉例:如果我們需要買國外的某一件商品A,這個時候我們一般有兩個途徑要麼直接去國外買,要麼可以找一些代購人員幫我們去購買。在這種情況下,我們由於直接去國外買,實在是太耗軟妹幣,而且還要花時間等等,這個時候我們最優的選擇就是找代購購買,這樣也幫我們省去了很多麻煩的事情。 ![](https://img2020.cnblogs.com/blog/1157447/202009/1157447-20200907175806312-1109486359.png) 代理模式類圖 ![](https://img2020.cnblogs.com/blog/1157447/202009/1157447-20200907175823435-2071777644.png) #### 程式碼示例 抽象物件: ```java public interface ITargetFactoryService { void sale(String name); } ``` 目標物件: ```java @Slf4j public class TargetFactoryServiceImpl implements ITargetFactoryService { @Override public void sale(String name) { log.info(name+"購買了商品A"); } } ``` 代理物件: ```java @Slf4j public class ProxyImpl implements ITargetFactoryService { public ITargetFactoryService service; public ProxyImpl(ITargetFactoryService service){ super(); this.service = service; } @Override public void sale(String name) { before(); service.sale("代購"); after(); } /** * 後置增強 */ private void after() { log.info("代購在購買後得到了市場調研結果"); } /** * 前置增強 */ private void before() { log.info("代購在購買前做了市場調研"); } } ``` 測試類: ```java @Slf4j @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, JdbcTemplateAutoConfiguration.class}) public class SpsringJdbcApplication { public static void main(String[] args) { TargetFactoryServiceImpl service = new TargetFactoryServiceImpl(); ProxyImpl proxy = new ProxyImpl(service); proxy.sale("代購"); SpringApplication.run(SpsringJdbcApplication.class, args); } } ``` 測試結果: ![](https://img2020.cnblogs.com/blog/1157447/202009/1157447-20200907175926767-488510418.png) 我們可以在程式碼示例中清晰的看到,在代理類中,代理物件包含了目標物件,並且在業務處理上進行了一定的業務擴充套件,但是卻和目標物件繼承於同一個介面。但是此擴充套件基於Spring AOP來講,以更加專業的叫法為前置增強、後置增強。 此類代理便是我們常說的靜態代理,靜態代理適合在業務比較簡單,實現類少,需求變化不頻繁,但是卻要對原有目標服務物件功能進行擴充套件,並且不去修改原有服務,這個時候我們就可以選擇使用靜態代理。 #### 靜態代理的缺點 如果此時我們業務需要進行擴充套件,我們的代購同學在經過市場調研以後,發現商品B更加受大家歡迎,這個時候我們就需要對自己的業務進行擴充套件了,怎麼擴充套件呢?一起接著往下看。 抽象物件: ```java public interface ITargetFactoryBService { void saleB(String name); } ``` 目標物件: ```java @Slf4j public class ITargetFactoryBServiceImpl implements ITargetFactoryBService { @Override public void saleB(String name) { log.info(name + "購買了商品B"); } } ``` 代理物件: ```java @Slf4j public class ProxyTwoImpl implements ITargetFactoryService, ITargetFactoryBService { public ITargetFactoryService service; public ITargetFactoryBService bService; public ProxyTwoImpl(ITargetFactoryService service,ITargetFactoryBService bService){ super(); this.service = service; this.bService = bService; } @Override public void sale(String name) { before(); service.sale("代購"); after(); } @Override public void saleB(String name) { before(); bService.saleB("代購"); after(); } /** * 後置增強 */ private void after() { log.info("代購在購買後得到了市場調研結果"); } /** * 前置增強 */ private void before() { log.info("代購在購買前做了市場調研"); } } ``` 測試類: ```java @Slf4j @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, JdbcTemplateAutoConfiguration.class}) public class SpsringJdbcApplication { public static void main(String[] args) { TargetFactoryServiceImpl service = new TargetFactoryServiceImpl(); ITargetFactoryBServiceImpl bService = new ITargetFactoryBServiceImpl(); ProxyTwoImpl proxy2 = new ProxyTwoImpl(service, bService); proxy2.sale("代購"); proxy2.saleB("代購"); SpringApplication.run(SpsringJdbcApplication.class, args); } } ``` 結果: ![](https://img2020.cnblogs.com/blog/1157447/202009/1157447-20200907180035992-920491862.png) 我們可以看到,在實現業務擴充套件的時候,需要對原有的代理類進行修改,如果後期我們需要擴充套件的業務較多的時候,這個類將變的更加繁雜,大量的繼承以及方法重寫,以至於牽一髮而動全身,所以在這種業務擴充套件性高、業務變化頻繁的情況下我們不建議使用靜態代理。 #### 靜態代理總結: 1、違反Java設計模式開閉原則,即:程式對外擴充套件開放,對修改關閉。當需求進行變更時,我們應該是新增程式碼塊來實現,而不是在原來的程式碼中進行修改實現。 2、擴充套件性很差。 3、可維護性差。 4、程式碼耦合度高。 如果覺著不錯可以關注公眾號:Java禿頭猿,專注於專案實際開發技術分享。 ![](https://img2020.cnblogs.com/blog/1157447/202009/1157447-20200907180217913-19904582