代理模式【介绍、静态代理、动态代理、入门、应用】
代理介紹
代理(Proxy)是一種設計模式, 提供了對目標對象另外的訪問方式;即通過代理訪問目標對象。 這樣好處: 可以在目標對象實現的基礎上,增強額外的功能操作。(擴展目標對象的功能)。
可以做到在不修改目標對象的功能前提下,對目標對象功能擴展。
簡單理解代理
很簡單舉個例子:
現在我是一個明星,擁有很多粉絲。粉絲希望我唱歌給他們聽,但是如果都是我來接應他們,我豈不是很忙….于是乎,我就去找了個經紀人。這個經紀人就代表了我。當粉絲想要我唱歌的時候,應該是找經紀人,告訴經紀人想讓我唱歌。
現在我越來越紅了,不是粉絲想要我唱歌,我就唱了。我要收費了。但是呢,作為一個公眾人物,不可能是我自己說:我要收10000萬,我才會去唱歌。于是這就讓經紀人對粉絲說:只有10000萬,我才會唱歌。
無論外界是想要我干什么,都要經過我的經紀人。我的經紀人也會在其中考慮收費、推脫它們的請求。
經紀人就是代理,實際上臺唱歌、表演的還是我
靜態代理
直接使用例子來說明吧…現在我有一個IUserDao的接口,擁有save方法()
// 接口 public interface IUserDao {void save(); }- UserDao實現該接口,重寫save()方法
現在,我想要在save()方法保存數據前開啟事務、保存數據之后關閉事務…(當然啦,直接再上面寫不就行了嗎…業務方法少的時候,確實沒毛病…)
public void save() {System.out.println("開啟事務");System.out.println("-----已經保存數據!!!------");System.out.println("關閉事務");}但是呢,現在如果我有好多好多個業務方法都需要開啟事務、關閉事務呢?
public void save() {System.out.println("開啟事務");System.out.println("-----已經保存數據!!!------");System.out.println("關閉事務");}public void delete() {System.out.println("開啟事務");System.out.println("-----已經保存數據!!!------");System.out.println("關閉事務");}public void update() {System.out.println("開啟事務");System.out.println("-----已經保存數據!!!------");System.out.println("關閉事務");}public void login() {System.out.println("開啟事務");System.out.println("-----已經保存數據!!!------");System.out.println("關閉事務");}…..我們發現就有了很多很多的重復代碼了…我們要做的就是:當用戶調用UserDao方法的時候,找的是代理對象、而代理幫我在解決這么繁瑣的代碼
于是呢,我們就請了一個代理了
- 這個代理要和userDao有相同的方法…沒有相同的方法的話,用戶怎么調用啊??
- 代理只是對userDao進行增強,真正做事的還是userDao..
因此,我們的代理就要實現IUserDao接口,這樣的話,代理就跟userDao有相同的方法了。
public class UserDaoProxy implements IUserDao{// 接收保存目標對象【真正做事的還是UserDao】,因此需要維護userDao的引用private IUserDao target;public UserDaoProxy(IUserDao target) {this.target = target;}@Overridepublic void save() {System.out.println("開始事務...");target.save(); // 執行目標對象的方法System.out.println("提交事務...");} }外界并不是直接去找UserDao,而是要通過代理才能找到userDao
public static void main(String[] args) {// 目標對象IUserDao target = new UserDao();// 代理IUserDao proxy = new UserDaoProxy(target);proxy.save(); // 執行的是,代理的方法}這樣一來,我們在UserDao中就不用寫那么傻逼的代碼了…傻逼的事情都交給代理去干了…
為什么要用動態代理?
我們首先來看一下靜態代理的不足:
- 如果接口改了,代理的也要跟著改,很煩!
- 因為代理對象,需要與目標對象實現一樣的接口。所以會有很多代理類,類太多。
動態代理比靜態代理好的地方:
- 代理對象,不需要實現接口【就不會有太多的代理類了】
- 代理對象的生成,是利用JDKAPI, 動態地在內存中構建代理對象(需要我們指定創建 代理對象/目標對象 實現的接口的類型;)
動態代理快速入門
Java提供了一個Proxy類,調用它的newInstance方法可以生成某個對象的代理對象,該方法需要三個參數:
- 參數一:生成代理對象使用哪個類裝載器【一般我們使用的是代理類的裝載器】
- 參數二:生成哪個對象的代理對象,通過接口指定【指定要代理類的接口】
- 參數三:生成的代理對象的方法里干什么事【實現handler接口,我們想怎么實現就怎么實現】
在編寫動態代理之前,要明確兩個概念:
- 代理對象擁有目標對象相同的方法【因為參數二指定了對象的接口】
- 用戶調用代理對象的什么方法,都是在調用處理器的invoke方法。
- 使用JDK動態代理必須要有接口【參數二需要接口】
對象
小明是一個明星,擁有唱歌和跳舞的方法。實現了人的接口
public class XiaoMing implements Person {@Overridepublic void sing(String name) {System.out.println("小明唱" + name);}@Overridepublic void dance(String name) {System.out.println("小明跳" + name);} }接口
public interface Person {void sing(String name);void dance(String name); }代理類
public class XiaoMingProxy {//代理只是一個中介,實際干活的還是小明,于是需要在代理類上維護小明這個變量XiaoMing xiaoMing = new XiaoMing();//返回代理對象public Person getProxy() {/*** 參數一:代理類的類加載器* 參數二:被代理對象的接口* 參數三:InvocationHandler實現類*/return (Person)Proxy.newProxyInstance(XiaoMingProxy.class.getClassLoader(), xiaoMing.getClass().getInterfaces(), new InvocationHandler() {/*** proxy : 把代理對象自己傳遞進來* method:把代理對象當前調用的方法傳遞進來* args:把方法參數傳遞進來*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//如果別人想要讓小明唱歌if (method.getName().equals("sing")) {System.out.println("給1000萬來再唱");//實際上唱歌的還是小明method.invoke(xiaoMing, args);}return null;}});} }測試類
public static void main(String[] args) {//外界通過代理才能讓小明唱歌XiaoMingProxy xiaoMingProxy = new XiaoMingProxy();Person proxy = xiaoMingProxy.getProxy();proxy.sing("我愛你");}動態代理應用
我們之前寫中文過濾器的時候,需要使用包裝設計模式來設計一個request類。如果不是Servlet提供了實現類給我們,我們使用包裝設計模式會出現麻煩
現在我們學習了動態代理了,動態代理就是攔截直接訪問對象,可以給對象進行增強的一項技能
中文過濾器
public void doFilter(final ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {final HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) resp;response.setContentType("text/html;charset=UTF-8");request.setCharacterEncoding("UTF-8");//放出去的是代理對象chain.doFilter((ServletRequest) Proxy.newProxyInstance(CharacterEncodingFilter.class.getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//判斷是不是getParameter方法if (!method.getName().equals("getParameter")) {//不是就使用request調用return method.invoke(request, args);}//判斷是否是get類型的if (!request.getMethod().equalsIgnoreCase("get")) {return method.invoke(request, args);}//執行到這里,只能是get類型的getParameter方法了。String value = (String) method.invoke(request, args);if (value == null) {return null;}return new String(value.getBytes("ISO8859-1"), "UTF-8");}}), response);}轉載于:https://www.cnblogs.com/zhong-fucheng/p/7202998.html
總結
以上是生活随笔為你收集整理的代理模式【介绍、静态代理、动态代理、入门、应用】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2014025689《嵌入式程序设计》第
- 下一篇: openSUSE中启用apache mo