一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

吃透Java中的動(dòng)態(tài)代理

 風(fēng)_宇星 2014-03-13

動(dòng)態(tài)代理在Java中是很重要的一部分,在很多框架中都會(huì)用到,如Spring中的AOP、Hadoop中的RPC等。為此在這把我對(duì)Java中的動(dòng)態(tài)代理的理解分享給大家,同時(shí)寫了一個(gè)模擬AOP編程的實(shí)例。(Demo實(shí)例提供下載)

 

引入場(chǎng)景

如果要對(duì)第三方提供的JAR包中的某個(gè)類中的某個(gè)方法的前后加上自己的邏輯,比如打LOG,注意此時(shí)我們只有第三方提供的CLASS文件,因此根本不可能去修改別人的源代碼,那該怎么辦?

有兩種方法可以實(shí)現(xiàn),一種是利用繼承,另一種是利用聚合。舉例說明:

假設(shè)第三方中提供一個(gè)Run接口,里面只一個(gè)run方法,以及它的實(shí)現(xiàn)類Person。

Run.java

Java代碼  收藏代碼
  1. <span style="font-size: 14px;">package com.cloud.proxy.example;  
  2.   
  3. public interface Run {  
  4.     public void run();  
  5. }</span>  

 Person.java

Java代碼  收藏代碼
  1. <span style="font-size: 14px;">package com.cloud.proxy.example;  
  2.   
  3. public class Person implements Run {  
  4.   
  5.     @Override  
  6.     public void run() {  
  7.         System.out.println("person running...");  
  8.     }  
  9.   
  10. }</span>  

 第一種利用繼承實(shí)現(xiàn)

SuperMan1.java

Java代碼  收藏代碼
  1. <span style="font-size: 14px;">package com.cloud.proxy.example;  
  2.   
  3. public class SuperMan1 extends Person {  
  4.   
  5.     @Override  
  6.     public void run() {  
  7.         //方法開始前打LOG  
  8.         LOG.info("super man1 before run...");  
  9.         super.run();  
  10.         //方法結(jié)束后打LOG  
  11.         LOG.info("super man1 after run...");  
  12.     }  
  13.   
  14. }</span>  

 第二種利用聚合實(shí)現(xiàn)

SuperMan2.java

Java代碼  收藏代碼
  1. <span style="font-size: 14px;">package com.cloud.proxy.example;  
  2.   
  3. public class SuperMan2 implements Run {  
  4.     private Run person;  
  5.   
  6.     public SuperMan2(Run person) {  
  7.         this.person = person;  
  8.     }  
  9.   
  10.     @Override  
  11.     public void run() {  
  12.         //方法開始前打LOG  
  13.         LOG.info("super man2 before run...");  
  14.         person.run();  
  15.         //方法結(jié)束后打LOG  
  16.         LOG.info("super man2 after run...");  
  17.     }  
  18.   
  19. }</span>  

 這兩種實(shí)現(xiàn)方式,哪一種更好呢?

顯然是第二種利用聚合實(shí)現(xiàn)方法好,因?yàn)檫@種方式很靈活,同時(shí)又不會(huì)有多層的父子類關(guān)系。而繼承最不好的地方就是不靈活,同時(shí)會(huì)很容易形成臃腫的父子類關(guān)系,不利于后期的維護(hù)。

 

點(diǎn)題

其實(shí)SuperMan1類和SuperMan2類都是Person類的代理類,對(duì)Person類中的方法進(jìn)行加強(qiáng),只不過這種代理是靜態(tài)代理,很受限制。因?yàn)镾uperMan1和SuperMan2只能代理Run類型的類,其它類型沒法代理。為了解決這個(gè)問題,Java中引入動(dòng)態(tài)代理。

 

理解動(dòng)態(tài)代理

看了上面的分析,動(dòng)態(tài)代理的意思就是一個(gè)類的(比如Person)的代理類(比如SuperMan2)是動(dòng)態(tài)生成的,也就是說這個(gè)代理類不是提前寫好的,是在程序運(yùn)行時(shí)動(dòng)態(tài)的生成的。而且能夠代理實(shí)現(xiàn)了某個(gè)接口的任何類型的類。我們暫且把動(dòng)態(tài)代理這個(gè)過程當(dāng)作一個(gè)黑箱子,然后看它的輸入和輸出。對(duì)于輸入,就是要被代理的類和它實(shí)現(xiàn)的接口,對(duì)于輸出就是代理類,如圖所示:



 分析動(dòng)態(tài)代理過程

根據(jù)上圖,我們大致可以得知?jiǎng)討B(tài)代理會(huì)有這樣的過程:

1.根據(jù)輸入的接口,利用反射機(jī)制,肯定可以拿到有哪些方法;

2.根據(jù)輸入的被代理類,同樣利用反射機(jī)制,肯定去調(diào)用其實(shí)現(xiàn)的方法。

到了這里,好像少了一點(diǎn)東西,就是少了對(duì)某個(gè)方法的前后的加強(qiáng)的邏輯。那么該如何解決這個(gè)問題呢?為此,我們必須對(duì)輸入進(jìn)行改造,如圖:



 看圖我們可以發(fā)現(xiàn),被代理類不是直接給黑箱子了,而是先給Handler這樣的一個(gè)類,再給黑箱子,那么在Handler類中我們就是添加相應(yīng)的加強(qiáng)的邏輯了。

 

Java中的動(dòng)態(tài)代理

其實(shí)上面對(duì)動(dòng)態(tài)代理的分析過程,也就是Java中動(dòng)態(tài)代理的過程。我們來一一對(duì)應(yīng)一下:

黑箱子:就是Java中的Proxy類;

Handler:就是Java中的InvocationHandler的子類。

利用Proxy類中的newProxyInstance靜態(tài)方法,就可以動(dòng)態(tài)生成一個(gè)代理類。這個(gè)方法有三個(gè)參數(shù):

第一個(gè)是要一個(gè)類加載器,它的作用是將動(dòng)態(tài)生成的代理類的字節(jié)碼文件加載到JVM虛擬機(jī)中,一般我們可以用被代理類的加載器;

第二個(gè)是被代理類實(shí)現(xiàn)的接口的Class類;

第三個(gè)是InvocationHandler的子類,在這個(gè)類中的invoke方法中,對(duì)某個(gè)方法的前后加入加強(qiáng)的邏輯。

 

實(shí)例

這個(gè)實(shí)例是簡(jiǎn)單的模擬Spring是的AOP機(jī)制,即只要我們?cè)谂渲梦募蜷_了事務(wù)機(jī)制,那么在調(diào)用方法時(shí)就會(huì)開啟事務(wù),同樣我們?cè)谂渲梦募P(guān)閉了事務(wù)機(jī)制,那么在調(diào)用方法時(shí)就不會(huì)開啟事務(wù)了。

 

AOP.java

Java代碼  收藏代碼
  1. <span style="font-size: 14px;">package com.cloud.proxy;  
  2.   
  3. public interface AOP {  
  4.     public void show(String str);  
  5.     public String say(String str);  
  6. }</span>  

 AOPImpl,java

Java代碼  收藏代碼
  1. <span style="font-size: 14px;">package com.cloud.proxy;  
  2.   
  3. public class AOPImpl implements AOP {  
  4.   
  5.     @Override  
  6.     public void show(String str) {  
  7.         System.out.println("show: " + str);  
  8.     }  
  9.   
  10.     @Override  
  11.     public String say(String str) {  
  12.         return "say: " + str;  
  13.     }  
  14.   
  15. }</span>  

 AOPHandler.java

Java代碼  收藏代碼
  1. <span style="font-size: 14px;">package com.cloud.proxy;  
  2.   
  3. import java.lang.reflect.InvocationHandler;  
  4. import java.lang.reflect.Method;  
  5. import java.util.Map;  
  6.   
  7. public class AOPHandler implements InvocationHandler {  
  8.     private Object obj;  
  9.     private boolean flag;  
  10.   
  11.     public AOPHandler(Object obj) {  
  12.         this.obj = obj;  
  13.     }  
  14.   
  15.     public void setFlag(Map<String, String> config) {  
  16.         if (null == config) {  
  17.             flag = false;  
  18.         } else {  
  19.             if (config.containsKey("transaction") && "true".equalsIgnoreCase(config.get("transaction"))) {  
  20.                 flag = true;  
  21.             } else {  
  22.                 flag = false;  
  23.             }  
  24.         }  
  25.     }  
  26.   
  27.     @Override  
  28.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  29.         if (flag) {  
  30.             doBefore();  
  31.         }  
  32.         Object result = method.invoke(obj, args);  
  33.         if (flag) {  
  34.             doAfter();  
  35.         }  
  36.         return result;  
  37.     }  
  38.   
  39.     private void doBefore() {  
  40.         System.out.println("Transaction start...");  
  41.     }  
  42.   
  43.     private void doAfter() {  
  44.         System.out.println("Transaction commit...");  
  45.     }  
  46. }</span>  

 Client.java

Java代碼  收藏代碼
  1. <span style="font-size: 14px;">package com.cloud.proxy;  
  2.   
  3. import java.lang.reflect.Proxy;  
  4.   
  5. import com.cloud.proxy.util.JVMCache;  
  6.   
  7. public class Client {  
  8.   
  9.     public static void main(String[] args) throws Exception {  
  10.         AOPImpl impl = new AOPImpl();  
  11.         AOPHandler handler = new AOPHandler(impl);  
  12.         handler.setFlag(JVMCache.getConfig());  
  13.         AOP aop = (AOP) Proxy.newProxyInstance(AOPImpl.class.getClassLoader(), new Class<?>[] {AOP.class}, handler);  
  14.         aop.show("cloud");  
  15.         String result = aop.say("芝加哥09");  
  16.         System.out.println(result);  
  17.     }  
  18. }</span>  

 JVMCache.java

Java代碼  收藏代碼
  1. <span style="font-size: 14px;">package com.cloud.proxy.util;  
  2.   
  3. import java.util.Map;  
  4.   
  5. public class JVMCache {  
  6.   
  7.     private static Map<String, String> config;  
  8.   
  9.     public synchronized static Map<String, String> getConfig() throws Exception {  
  10.         if (null == config) {  
  11.             config = XMLUtil.parseXML();  
  12.         }  
  13.         return config;  
  14.     }  
  15. }</span>  

 XMLUtil.java

Java代碼  收藏代碼
  1. <span style="font-size: 14px;">package com.cloud.proxy.util;  
  2.   
  3. import java.io.InputStream;  
  4. import java.util.HashMap;  
  5. import java.util.Map;  
  6.   
  7. import javax.xml.parsers.DocumentBuilder;  
  8. import javax.xml.parsers.DocumentBuilderFactory;  
  9.   
  10. import org.w3c.dom.Document;  
  11. import org.w3c.dom.Element;  
  12. import org.w3c.dom.Node;  
  13. import org.w3c.dom.NodeList;  
  14.   
  15. public class XMLUtil {  
  16.   
  17.     public static Map<String, String> parseXML() throws Exception {  
  18.         Map<String, String> result = new HashMap<String, String>();  
  19.         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();  
  20.         DocumentBuilder db = dbf.newDocumentBuilder();  
  21.   
  22.         InputStream in = XMLUtil.class.getClassLoader().getResourceAsStream("config.xml");  
  23.         Document document = db.parse(in);  
  24.         Element root = document.getDocumentElement();  
  25.         NodeList xmlNodes = root.getChildNodes();  
  26.         for (int i = 0; i < xmlNodes.getLength(); i++) {  
  27.             Node config = xmlNodes.item(i);  
  28.             if (null != config && config.getNodeType() == Node.ELEMENT_NODE) {  
  29.                 String nodeName = config.getNodeName();  
  30.                 if ("transaction".equals(nodeName)) {  
  31.                     String textContent = config.getTextContent();  
  32.                     result.put("transaction", textContent);  
  33.                 }  
  34.             }  
  35.         }  
  36.         return result;  
  37.     }  
  38. }</span>  

 config.xml

Xml代碼  收藏代碼
  1. <span style="font-size: 14px;"><?xml version="1.0" encoding="UTF-8"?>  
  2. <config>  
  3.     <transaction>true</transaction>  
  4. </config></span>  

 

運(yùn)行結(jié)果

當(dāng)config.xml文件中配置為true時(shí),運(yùn)行結(jié)果:

運(yùn)行結(jié)果代碼  收藏代碼
  1. <span style="font-size: 14px;">Transaction start...  
  2. show: cloud  
  3. Transaction commit...  
  4. Transaction start...  
  5. Transaction commit...  
  6. say: 芝加哥09</span>  

 我們可以發(fā)現(xiàn),在執(zhí)行每個(gè)方法的前會(huì)開啟事務(wù),每個(gè)方法后提交事務(wù)。

 

當(dāng)config.xml文件中配置為false時(shí),運(yùn)行結(jié)果:

運(yùn)行結(jié)果代碼  收藏代碼
  1. <span style="font-size: 14px;">show: cloud  
  2. say: 芝加哥09</span>  

 我們可以發(fā)現(xiàn)這樣就可以將事務(wù)機(jī)制關(guān)掉。

這樣我們模擬了一個(gè)AOP編程。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    欧美熟妇一区二区在线| 亚洲一区二区三区一区| 欧美亚洲国产日韩一区二区| 中文字幕不卡欧美在线| 免费在线观看激情小视频 | 日本中文在线不卡视频| 午夜福利视频六七十路熟女| 富婆又大又白又丰满又紧又硬| 久热久热精品视频在线观看| 男女午夜视频在线观看免费| 欧美日韩视频中文字幕| 久久中文字人妻熟女小妇| 亚洲熟妇熟女久久精品| 国产伦精品一区二区三区高清版| 国产精品白丝久久av| 日韩欧美精品一区二区三区| 日本91在线观看视频| 国产中文字幕一二三区| 日本人妻免费一区二区三区| 亚洲成人黄色一级大片| 久热青青草视频在线观看| 免费观看成人免费视频| 国产精品第一香蕉视频| 韩国激情野战视频在线播放| 精品精品国产欧美在线| 中文字幕日韩欧美理伦片| 成人午夜视频精品一区| 日本美国三级黄色aa| 国产激情一区二区三区不卡| 中国一区二区三区人妻| 国产日韩欧美在线播放| 麻豆91成人国产在线观看| 日韩aa一区二区三区| 老司机精品线观看86| 亚洲国产91精品视频| 国产日韩欧美综合视频| 婷婷开心五月亚洲综合| 91精品国产综合久久不卡| 日韩一区二区三区免费av| 亚洲熟女国产熟女二区三区| 国产精品久久精品毛片|