靜態代理設計與動態代理設計

靜態代理設計模式

代理設計模式最本質的特質:一個真實業務主題只完成核心操作,而所有與之輔助的功能都由代理類來完成。

?

例如,在進行數據庫更新的過程之中,事務處理必須起作用,所以此時就可以編寫代理設計模式來完成。

?

范例:結合傳統的代理設計模式以及以購物車CartDao為例來編寫代理設計模式

package so.strong.mall.proxy;
import java.util.List;
public interface CartDao {boolean insert(Cart cart) throws Exception;List<Cart> findAll() throws Exception;
}

以上CartDao接口定義的方法,更行插入一定需要事務控制,對于查詢操作,不需要事務控制。

?

定義CartDao真實實現

package so.strong.mall.proxy;
import java.util.List;
public class CartDAOImpl implements CartDao{@Overridepublic boolean insert(Cart cart) throws Exception {System.out.println("=====執行數據增加操作=====");return false;}@Overridepublic List<Cart> findAll() throws Exception {System.out.println("=====執行數據列表操作=====");return null;}
}

?

定義代理主題類

package so.strong.mall.proxy;
import java.util.List;
public class CartDAOProxy implements CartDao {private CartDao cartDao;public CartDAOProxy() {}public void setCartDao(CartDao cartDao) {this.cartDao = cartDao;}public void prepare() {System.out.println("=====取消掉jdbc的自動提交");}public void commit() {System.out.println("=====手工提交事務");}public void rollback() {System.out.println("=====出現錯誤,事務回滾");}@Overridepublic boolean insert(Cart cart) throws Exception {try {this.prepare();boolean flag = this.cartDao.insert(cart);this.commit();return flag;} catch (Exception e) {this.rollback();throw e;}}@Overridepublic List<Cart> findAll() throws Exception {return this.cartDao.findAll();}
}

?

業務層現在并不關心到底是代理類還是真實主題類,它只關心一點,只要取得了CartDao接口對象就可以,那么這一操作可以通過工廠類來隱藏。

package so.strong.mall.proxy;
public class DAOFactory {public static CartDao getCartDaoInstance() {CartDAOProxy proxy = new CartDAOProxy();proxy.setCartDao(new CartDAOImpl());return proxy;}
}

此時業務層暫時不需要繼續進行,只需要通過客戶端模擬業務層調用即可。

public class TestDemo {
public static void main(String[] args) throws Exception{CartDao dao = DAOFactory.getCartDaoInstance();dao.insert(new Cart());}
}
//=====取消掉jdbc的自動提交
//=====執行數據增加操作=====
//=====手工提交事務

因為事務和處理本身與核心業務有關的功能,但是它不是核心,那么用代理解決是最合適的方式。

?

動態代理設計模式

上面給出的代理設計模式的確可以完成代理要求,但是有一個問題:如果說現在項目里面有200張數據表,那么至少也需要200個左右的DAO接口,如果用上面的代理設計模式,那么意味著除了編寫200個的DAO接口實現,還要編寫200個代理類,并且有意思的是,這些代理類實現幾乎相同。

以上的代理設計模式屬于靜態代理設計模式,只能夠作為代理模式的雛形出現,并不能購作為代碼使用的設計模式,為此專門引入了動態代理設計模式的概念。

即:利用一個代理類可以實現所有被代理的操作。

?

如果要想實現動態設計模式,那么必須首先觀察一個接口:java.lang.reflect.InvocatonHandler. ? 它里面有一個方法

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

這個方法就屬于代理中調用真實主題類的操作方法,這個方法里面的參數意義如下:

  • Object proxy:表示代理類的對象;
  • Method method:表示現在正在調用的方法;
  • Object[] args:表示方法里面的參數。

但是這個方法沒有所對應的真實對象,所以需要在創建這個類對象的時候設置好真實代理對象。

?

如果要想找到代理對象則要使用java.lang.reflect.Proxy類來動態創建,此類主要使用以下方法:

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException

此方法參數定義如下:

  • ClassLoader loader :指的是取得對象的加載器;
  • Class<?>[] interfaces: 代理設計模式的核心是圍繞接口進行的,所以此處必須取出全部的接口;
  • InvocationHandler h:代理的實現類。

?

范例:使用動態代理實現上面的代理

CartDao不變,修改CartDAOProxy代理類

package so.strong.mall.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class CartDAOProxy implements InvocationHandler {private Object obj; //這個是真實對象主題/*** 將要操作的真實主題對象綁定到代理之中,而后返回一個代理類對象* @param obj 真實對象主題* @return 代理類對象*/public Object bind(Object obj) {this.obj = obj;return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(), this);}public void prepare() {System.out.println("=====取消掉jdbc的自動提交");}public void commit() {System.out.println("=====手工提交事務");}public void rollback() {System.out.println("=====出現錯誤,事務回滾");}//只要執行了操作方法,那么就一定會觸發invoke
    @Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object object = null;//接收返回值if (method.getName().contains("insert")) { //更新插入類操作this.prepare();try {object = method.invoke(this.obj, args); //反射調用方法this.commit();} catch (Exception e) {this.rollback();}} else {object = method.invoke(this.obj, args);//查詢操作不需要事務支持
        }return object;}
}
//修改工廠
package so.strong.mall.proxy;
public class DAOFactory {public static Object getCartDaoInstance(Object realObject) {return new CartDAOProxy().bind(realObject);}
}
//修改調用
package so.strong.mall.proxy;
public class TestDemo {public static void main(String[] args) throws Exception{CartDao dao =(CartDao) DAOFactory.getCartDaoInstance(new CartDAOImpl());dao.insert(new Cart());}
}

?

CGLIB實現動態代理設計模式

動態代理模式的確好用,而且也解決了代理類重復的問題,但是不管是傳統靜態代理或動態代理都有個設計缺陷,以動態代理為例:

return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this); //傳入真實主題類,返回代理主題類

代理設計模式有一個硬性要求,就是類必須要有接口,所以業界很多人認為應該在沒有接口的環境下也能使用代理設計模式。

所以在此時在開源社區里面提供了一個組件包——CGLIB,利用此包可以在沒有接口的情況下也能夠使用動態代理設計模式,它是模擬的類。

如果要想使用CGLIB,那么必須首先搞清楚對應關系:

  • Proxy:net.sf.cglib.proxy.Enhancer
  • InvocationHandler:net.sf.cglib.proxy.MethodInterceptor
  • 真實主題調用:net.sf.cglib.proxy.MethodProxy

老師課上使用的是引入CGLIB的jar包,我去mvn倉庫找了一下,找到了一個cglib,放到pom里面發現也可以。

 <dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.2.2</version>
</dependency>

?

范例:使用CGLIB實現動態代理設計模式

package so.strong.mall.proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;class ItemDAOImpl {public void insert(Item item) {System.out.println("=====增加操作=====");}
}class MyProxy implements MethodInterceptor {private Object target; //真實操作主題public MyProxy(Object target) {this.target = target;}@Overridepublic Object intercept(Object proxy, Method method, Object[] args,MethodProxy methodProxy) throws Throwable {Object object = null;this.prepare();object = method.invoke(this.target, args);this.commit();return object;}public void prepare() {System.out.println("=====取消掉jdbc的自動提交=====");}public void commit() {System.out.println("=====手工提交事務=====");}
}public class TestCGLIB {public static void main(String[] args) {ItemDAOImpl itemDAO = new ItemDAOImpl(); //真實主題對象//代理設計模式之中必須要有公共的集合點,例如:接口,而CGLIB沒有接口Enhancer enhancer = new Enhancer(); //創建一個代理工具類enhancer.setSuperclass(ItemDAOImpl.class); //設置一個虛擬的父類enhancer.setCallback(new MyProxy(itemDAO)); //設置代理的回調操作ItemDAOImpl proxyDao = (ItemDAOImpl) enhancer.create();proxyDao.insert(new Item());}
}

可以發現此時沒有了對接口的依賴,也可以實現動態代理設計,但是需要模擬代理的父類對象。

轉載于:https://www.cnblogs.com/itermis/p/8940582.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/390591.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/390591.shtml
英文地址,請注明出處:http://en.pswp.cn/news/390591.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

svm機器學習算法_SVM機器學習算法介紹

svm機器學習算法According to OpenCVs "Introduction to Support Vector Machines", a Support Vector Machine (SVM):根據OpenCV“支持向量機簡介”&#xff0c;支持向量機(SVM)&#xff1a; ...is a discriminative classifier formally defined by a separating …

6.3 遍歷字典

遍歷所有的鍵—值對 遍歷字典時&#xff0c;鍵—值對的返回順序也與存儲順序不同。 6.3.2 遍歷字典中的所有鍵 在不需要使用字典中的值時&#xff0c;方法keys() 很有用。 6.3.3 按順序遍歷字典中的所有鍵 要以特定的順序返回元素&#xff0c;一種辦法是在for 循環中對返回的鍵…

Google Guava新手教程

以下資料整理自網絡 一、Google Guava入門介紹 引言 Guavaproject包括了若干被Google的 Java項目廣泛依賴 的核心庫&#xff0c;比如&#xff1a;集合 [collections] 、緩存 [caching] 、原生類型支持 [primitives support] 、并發庫 [concurrency libraries] 、通用注解 [comm…

HTML DOM方法

querySelector() (querySelector()) The Document method querySelector() returns the first element within the document that matches the specified selector, or group of selectors. If no matches are found, null is returned.Document方法querySelector()返回文檔中與…

leetcode 773. 滑動謎題

題目 在一個 2 x 3 的板上&#xff08;board&#xff09;有 5 塊磚瓦&#xff0c;用數字 1~5 來表示, 以及一塊空缺用 0 來表示. 一次移動定義為選擇 0 與一個相鄰的數字&#xff08;上下左右&#xff09;進行交換. 最終當板 board 的結果是 [[1,2,3],[4,5,0]] 謎板被解開。…

數據科學領域有哪些技術_領域知識在數據科學中到底有多重要?

數據科學領域有哪些技術Jeremie Harris: “In a way, it’s almost like a data scientist or a data analyst has to be like a private investigator more than just a technical person.”杰里米哈里斯(Jeremie Harris) &#xff1a;“ 從某種意義上說&#xff0c;這就像是數…

python 算術運算

1. 算術運算符與優先級 # -*- coding:utf-8 -*-# 運算符含有,-,*,/,**,//,% # ** 表示^ , 也就是次方 a 2 ** 4 print 2 ** 4 , aa 16 / 5 print 16 / 5 , aa 16.0 / 5 print 16.0 / 5 , a# 結果再進行一次floor a 16.0 // 5.0 print 16.0 // 5.0 , aa 16 // 5 print …

c語言編程時碰到取整去不了_碰到編程墻時如何解開

c語言編程時碰到取整去不了Getting stuck is part of being a programmer, no matter the level. The so-called “easy” problem is actually pretty hard. You’re not exactly sure how to move forward. What you thought would work doesn’t.無論身在何處&#xff0c;陷…

初創公司怎么做銷售數據分析_為什么您的初創企業需要數據科學來解決這一危機...

初創公司怎么做銷售數據分析The spread of coronavirus is delivering a massive blow to the global economy. The lockdown and work from home restrictions have forced thousands of startups to halt expansion plans, cancel services, and announce layoffs.冠狀病毒的…

leetcode 909. 蛇梯棋

題目 N x N 的棋盤 board 上&#xff0c;按從 1 到 N*N 的數字給方格編號&#xff0c;編號 從左下角開始&#xff0c;每一行交替方向。 例如&#xff0c;一塊 6 x 6 大小的棋盤&#xff0c;編號如下&#xff1a; r 行 c 列的棋盤&#xff0c;按前述方法編號&#xff0c;棋盤格…

Python基礎之window常見操作

一、window的常見操作&#xff1a; cd c:\ #進入C盤d: #從C盤切換到D盤 cd python #進入目錄cd .. #往上走一層目錄dir #查看目錄文件列表cd ../.. #往上上走一層目錄 二、常見的文件后綴名&#xff1a; .txt 記事本文本文件.doc word文件.xls excel文件.ppt PPT文件.exe 可執行…

WPF效果(GIS三維篇)

二維的GIS已經被我玩爛了&#xff0c;緊接著就是三維了&#xff0c;哈哈&#xff01;先來看看最簡單的效果&#xff1a; 轉載于:https://www.cnblogs.com/OhMonkey/p/8954626.html

css注釋_CSS注釋示例–如何注釋CSS

css注釋Comments are used in CSS to explain a block of code or to make temporary changes during development. The commented code doesn’t execute.CSS中使用注釋來解釋代碼塊或在開發過程中進行臨時更改。 注釋的代碼不執行。 Both single and multi-line comments in…

r軟件時間序列分析論文_高度比較的時間序列分析-一篇論文評論

r軟件時間序列分析論文數據科學 &#xff0c; 機器學習 (Data Science, Machine Learning) In machine learning with time series, using features extracted from series is more powerful than simply treating a time series in a tabular form, with each date/timestamp …

leetcode 168. Excel表列名稱

題目 給你一個整數 columnNumber &#xff0c;返回它在 Excel 表中相對應的列名稱。 例如&#xff1a; A -> 1 B -> 2 C -> 3 … Z -> 26 AA -> 27 AB -> 28 … 示例 1&#xff1a; 輸入&#xff1a;columnNumber 1 輸出&#xff1a;“A” 示例 2&…

飛機訂票系統

1 #include <stdio.h>2 #include <stdlib.h>3 #include <string.h>4 #include <conio.h>5 typedef struct flightnode{6 char flight_num[10]; //航班號7 char start_time[10]; //起飛時間8 char end_time[10]; //抵達時間9 char st…

解決Mac10.13 Pod報錯 -bash: /usr/local/bin/pod: /System/Library/Frameworks/Ruby.fram

升級10.13以后Pod命令失效&#xff0c;解決辦法如下&#xff1a; 終端執行 brew link --overwrite cocoapods 復制代碼嘗試 Pod 命令是否已經恢復 若報錯繼續執行 brew reinstall cocoapodsbrew install rubybrew link --overwrite cocoapods 復制代碼嘗試 Pod 命令是否已經恢復…

angular示例_用示例解釋Angular動畫

angular示例為什么要使用動畫&#xff1f; (Why use Animations?) Modern web components frequently use animations. Cascading Style-sheets (CSS) arms developers with the tools to create impressive animations. Property transitions, uniquely named animations, mu…

selenium抓取_使用Selenium的網絡抓取電子商務網站

selenium抓取In this article we will go through a web scraping process of an E-Commerce website. I have designed this particular post to be beginner friendly. So, if you have no prior knowledge about web scraping or Selenium you can still follow along.在本文…

劍指 Offer 37. 序列化二叉樹

題目 序列化是將一個數據結構或者對象轉換為連續的比特位的操作&#xff0c;進而可以將轉換后的數據存儲在一個文件或者內存中&#xff0c;同時也可以通過網絡傳輸到另一個計算機環境&#xff0c;采取相反方式重構得到原數據。 請設計一個算法來實現二叉樹的序列化與反序列化…