日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java-代理模式的理解

發(fā)布時間:2024/4/13 java 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java-代理模式的理解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
  • 引言

    設計模式是語言的表達方式,它能讓語言輕便而富有內(nèi)涵、易讀卻功能強大。代理模式在Java中十分常見,有為擴展某些類的功能而使用靜態(tài)代理,也有如Spring實現(xiàn)AOP而使用動態(tài)代理,更有RPC實現(xiàn)中使用的調(diào)用端調(diào)用的代理服務。代理模型除了是一種設計模式之外,它更是一種思維,所以探討并深入理解這種模型是非常有必要的。

  • 代理模式拳譜總綱

     代理模式這種設計模式是一種使用代理對象來執(zhí)行目標對象的方法并在代理對象中增強目標對象方法的一種設計模式。代理對象代為執(zhí)行目標對象的方法,并在此基礎上進行相應的擴展。看起來是有點拗口,首先介紹一個原則:開閉原則(對擴展開放,對修改關閉)。一種好的設計模式甚至是架構,都是在不修改原有形態(tài)的基礎上擴展出新的功能。

    代理模式的元素是:共同接口、代理對象、目標對象。

    代理模式的行為:由代理對象執(zhí)行目標對象的方法、由代理對象擴展目標對象的方法。

    代理模式的宏觀特性:對客戶端只暴露出接口,不暴露它以下的架構。

    代理模式的微觀特性:每個元由三個類構成,如圖。

? ? ? ? ? ? ? ? ? ?

     代理模式的種類:靜態(tài)代理、動態(tài)代理(jdk動態(tài)代理、cglib動態(tài)代理、Spring和AspectJ實現(xiàn)的動態(tài)代理)

  • 靜態(tài)代理

     靜態(tài)代理模式就是如上圖所示,構造三個類實現(xiàn)他們的關系。

     首先會思考的一點就是為什么需要實現(xiàn)同一個接口,如果不實現(xiàn)同一個接口,一樣可以“代理”功能,所以為什么非要實現(xiàn)同一個接口。我個人認為不實現(xiàn)統(tǒng)一接口的話代理方法有可能會不能完全實現(xiàn)(因為實現(xiàn)接口必須實現(xiàn)它的抽象方法),其次就是方法名稱了,已經(jīng)由接口定義的方法就是目標對象實現(xiàn)了的功能,也算是一種提醒,最后我能想到的就是不實現(xiàn)統(tǒng)一接口的話應該叫做聚合而不是代理。

?

package Proxy.Static;public interface DAOInterface {public void add();public void delete();public void update();public void query(); }

?

package Proxy.Static;public class UserDao implements DAOInterface{@Overridepublic void add() {System.out.println("在目標對象中執(zhí)行add");}@Overridepublic void delete() {System.out.println("在目標對象中執(zhí)行delete");}@Overridepublic void update() {System.out.println("在目標對象中執(zhí)行update");}@Overridepublic void query() {System.out.println("在目標對象中執(zhí)行query");}} package Proxy.Static; /*** 代理對象* @author ctk**/ public class UserDaoProxy implements DAOInterface{UserDao userDao = null;public UserDaoProxy(UserDao userDao){this.userDao = userDao;}@Overridepublic void add() {userDao.add();System.out.println("記錄日志add");}@Overridepublic void delete() {userDao.delete();System.out.println("記錄日志delete");}@Overridepublic void update() {userDao.update();System.out.println("記錄日志update");}@Overridepublic void query() {userDao.query();System.out.println("記錄日志query");}}

    靜態(tài)代理就是寫死了在代理對象中執(zhí)行這個方法前后執(zhí)行添加功能的形式,每次要在接口中添加一個新方法,則需要在目標對象中實現(xiàn)這個方法,并且在代理對象中實現(xiàn)相應的代理方法,幸而Java有獨特的反射技術,可以實現(xiàn)動態(tài)代理。

  • 動態(tài)代理

     實際上在原理上講我只認識Jdk動態(tài)代理和Cglib動態(tài)代理,Spring和AspectJ的動態(tài)代理是基于前面兩種來實現(xiàn)的。

     Jdk的動態(tài)代理,是使用反射技術獲得類的加載器并且創(chuàng)建實例,根據(jù)類執(zhí)行的方法在執(zhí)行方法的前后發(fā)送通知。

     接口和實現(xiàn)類還是使用上面貼出來的。

     在代理對象Proxy的新建代理實例方法中,必須要獲得類的加載器、類所實現(xiàn)的接口、還有一個攔截方法的句柄。

     在句柄的invoke中如果不調(diào)用method.invoke則方法不會執(zhí)行。在invoke前后添加通知,就是對原有類進行功能擴展了。

     創(chuàng)建好代理對象之后,proxy可以調(diào)用接口中定義的所有方法,因為它們實現(xiàn)了同一個接口,并且接口的方法實現(xiàn)類的加載器已經(jīng)被反射框架獲取到了。

package Proxy.jdkProxy;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;public class Test {public static void main(String[] args) {DAOInterface userDao = new UserDao();DAOInterface proxy = (DAOInterface) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), new InvocationHandler() {//回調(diào)方法 攔截到目標對象的時候執(zhí)行 @Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("在 代理對象 中攔截到:"+method.getName());Object o = method.invoke(userDao, args);//調(diào)用攔截到的方法return o;}});proxy.delete();} }

?     另一種動態(tài)代理的實現(xiàn)方式是使用Cglib,所以得先導入兩個包

  

     實現(xiàn)方式如下

package Proxy.Cglib;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;/*** cglib代理 要求類不能使final 代理對象繼承目標對象* * @author ctk**/ public class Test {public static void main(String[] args) {UserDao target = new UserDao();Enhancer en = new Enhancer();//設置代理對象的父類 en.setSuperclass(target.getClass());//設置回調(diào)en.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {System.out.println("在 代理對象 中攔截到 "+arg1.getName());Object obj = arg1.invoke(target, arg2);return obj;}});UserDao proxy = (UserDao) en.create();proxy.add();} }

     Cglib實現(xiàn)代理的方式是和目標對象使用同一個父類,無論是繼承還是實現(xiàn)接口,都是為了代理對象能直接調(diào)用目標對象的方法。

  • RPC服務分離代理模式

      

     在分布式的書上看到RPC的誕生契機,任何一種技術干學都是不長進的,只有把它的前世今生給摸透了,才能有所領悟。當你的web應用達到了編譯一次1分鐘或者5分鐘或者更多的時候,你就該想到服務解耦這個辦法了。即使是在做一個ERP,但是業(yè)務多起來也是如C++編譯一樣的(不是黑C++哈哈),服務解耦的意義就是想,我這個web應用調(diào)用的service能不能不運行在同一個web應用中呢?RPC由此誕生了,本地保存一個調(diào)用列表,而真正執(zhí)行是在另外一個應用(或者另外一個服務器)。只要制定好通信框架序列化和反序列化的制度(私有協(xié)議棧),就做成了一個RPC框架。雖然如ActiveMQ之流的通信框架底層使用的是這種技術,但是它們的復雜程度也不是一個demo能說清楚的。

     服務調(diào)用方

package RPC;import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.net.InetSocketAddress; import java.net.Socket;public class RPCimporter<S> {@SuppressWarnings("unchecked")public S importer(final Class<?> serviceClass,final InetSocketAddress addr){return (S)Proxy.newProxyInstance(serviceClass.getClassLoader(), new Class<?>[]{serviceClass.getInterfaces()[0]}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Socket socket = null;ObjectOutputStream out = null;ObjectInputStream ins = null;try{socket = new Socket();socket.connect(addr);out = new ObjectOutputStream(socket.getOutputStream());out.writeUTF(serviceClass.getName());out.writeUTF(method.getName());out.writeObject(method.getParameterTypes());out.writeObject(args);ins = new ObjectInputStream(socket.getInputStream());return ins.readObject();}finally {if(out != null)out.close();if(ins != null)ins.close();if(socket != null)socket.close();}}});} }

     服務調(diào)用

package RPC;import java.io.IOException; import java.net.InetSocketAddress;/*** 測試RPCdemo* @author ctk**/ public class RPCTest {public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {try {RPCExporter.exporter("localhost", 10000);} catch (IOException e) {e.printStackTrace();}}}).start();RPCimporter<EchoService> importer = new RPCimporter<>();EchoService echo = importer.importer(EchoServiceImpl.class, new InetSocketAddress("localhost", 10000));System.out.println(echo.echo("hello world"));} }

     服務列表用接口來實現(xiàn)再好不過了,在調(diào)用importer這個方法的時候,會往提供方請求一個執(zhí)行服務的類和方法并要求返回一個執(zhí)行結果。

     服務提供方

package RPC; /*** RPC服務代理接口* @author MacBook**/ public interface EchoService {public String echo(String ping); } package RPC;public class EchoServiceImpl implements EchoService{@Overridepublic String echo(String ping) {return ping != null ? ping + " ---> I am ok.":"I am ok";}} package RPC;import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.util.concurrent.Executor; import java.util.concurrent.Executors;public class RPCExporter {static Executor executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());public static void exporter(String hostName,int port) throws IOException{ServerSocket server = new ServerSocket();server.bind(new InetSocketAddress(hostName, port));try{while(true){executor.execute(new ExportTask(server.accept()));}}catch (Exception e) {} finally {server.close();}}} package RPC;import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Method; import java.net.Socket;public class ExportTask implements Runnable {Socket client = null;public ExportTask(Socket socket){client = socket;}@Overridepublic void run() {ObjectInputStream oins = null;ObjectOutputStream oous = null;try{oins = new ObjectInputStream(client.getInputStream());String interfaceName = oins.readUTF();Class<?> service = Class.forName(interfaceName);String methodName = oins.readUTF();Class<?>[] parameterTypes = (Class<?>[])oins.readObject();Object[] arguments = (Object[])oins.readObject();Method method = service.getMethod(methodName, parameterTypes);Object result = method.invoke(service.newInstance(), arguments);oous = new ObjectOutputStream(client.getOutputStream());oous.writeObject(result);}catch (Exception e) {}finally {try {if(oins != null)oins.close();if(oous != null)oous.close();if(client != null)client.close();} catch (IOException e) {e.printStackTrace();}}}}

     服務器架構和BIO的多線程結構沒有什么區(qū)別,只是使用了線程池而已,把accept到的socket交給線程實現(xiàn)類去完成任務。在提供服務的時候先讀取請求的對象名和方法名,并通過反射創(chuàng)建實例,最后接受到參數(shù),運行結束之后返回result結果。

  • 一些感想

     以前覺得,設計模式只是為了代碼更加簡潔,或者實現(xiàn)功能更為有條理而設置的,現(xiàn)在慢慢感悟到框架的設計也可設計模式有緊密的關系。就比如生產(chǎn)者消費者模型和消息中間件的架構是密切相關的,相似的還有觀察者模型、發(fā)布訂閱模型。而RPC服務實現(xiàn)服務解耦也有點像代理模式的思想,雖然它沒有使用反射進行動態(tài)代理,沒有AOP那么直接。還有一點,就是不同場景下的設計模式需要做不同的思考,比如單例模式在高并發(fā)環(huán)境下應該如何達到高效、安全。

     多思考,多挖掘,干巴爹。

轉載于:https://www.cnblogs.com/chentingk/p/6433372.html

總結

以上是生活随笔為你收集整理的Java-代理模式的理解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。