看mybatis日誌模塊時涉及的動態代理

動態代理的使用和個人理解(再看spring aop前的理解)

動態代理調用一個方法,並且對這個方法進行增強,代碼如下

代碼如下,
  1. //接口
1package com.enjoylearning.proxy.unknow;
2
3public interface UnknowToolsFactory {
4    void saleUnknowTools(float length);
5}
  1. 接口實現
1package com.enjoylearning.proxy.unknow;
2
3public class DdFactory implements UnknowToolsFactory{
4    @Override
5    public void saleUnknowTools(float length) {
6        System.out.println("根據您的需求,爲您定製了一個高度爲:\"+length+\"的Unknow模特");
7    }
8}
  1. 動態代理類
 1package com.enjoylearning.proxy.unknow;
2
3import javax.annotation.Resource;
4import java.lang.reflect.InvocationHandler;
5import java.lang.reflect.Method;
6import java.lang.reflect.Proxy;
7
8public class LicmCompany implements InvocationHandler {
9
10    @Resource
11    private Object factory;
12
13    public Object getFactory() {
14        return factory;
15    }
16
17    public void setFactory(Object factory) {
18        this.factory = factory;
19    }
20
21    public Object getProxyInstance(){
22        return Proxy.newProxyInstance(factory.getClass().getClassLoader(),factory.getClass().getInterfaces(),this);
23    }
24
25
26    @Override
27    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
28        dosomeThingBefore();
29        Object obj = method.invoke(factory,args);
30        dosomeThingEnd();
31        return obj;
32    }
33
34    //售前服務
35    private void dosomeThingEnd() {
36        System.out.println("精美包裝,快遞一條龍服務!");
37    }
38
39    //售後服務
40    private void dosomeThingBefore() {
41        System.out.println("根據您的需求,進行市場調研和產品分析!");
42    }
43}
  1. 測試類,普通的main方法
1    UnknowToolsFactory unknowToolsFactory = new DdFactory();
2        LicmCompany licmCompany = new LicmCompany();
3        licmCompany.setFactory(unknowToolsFactory);
4        UnknowToolsFactory licm2 =  (UnknowToolsFactory)licmCompany.getProxyInstance();
5        licm2.saleUnknowTools(1.2f);
  1. 附一個工具類,動態生成的二進制字節碼保存到硬盤中
 1package com.enjoylearning.proxy.utils;
2
3import java.io.FileOutputStream;
4import java.io.IOException;
5import java.lang.reflect.Proxy;
6import sun.misc.ProxyGenerator;
7
8public class ProxyUtils {
9
10    /*
11     * 將根據類信息 動態生成的二進制字節碼保存到硬盤中, 默認的是clazz目錄下 params :clazz 需要生成動態代理類的類
12     * proxyName : 爲動態生成的代理類的名稱
13     */

14    public static void generateClassFile(Class clazz, String proxyName{
15
16
17        // 根據類信息和提供的代理類名稱,生成字節碼
18        byte[] classFile = ProxyGenerator.generateProxyClass(proxyName,
19                new Class[]{clazz});
20
21        String paths = clazz.getResource(".").getPath();
22        System.out.println(paths);
23        FileOutputStream out = null;
24
25        try {
26            // 保留到硬盤中
27            out = new FileOutputStream(paths + proxyName + ".class");
28//            out = new FileOutputStream("C:/a.class");
29            out.write(classFile);
30            out.flush();
31        } catch (Exception e) {
32            e.printStackTrace();
33        } finally {
34            try {
35                out.close();
36            } catch (IOException e) {
37                e.printStackTrace();
38            }
39        }
40    }
41
42}
需要注意的幾個方法
  1. 代碼結構,需要一個接口,實現類,實現invocationhandler的代理類
  2. 代理類中的public Object invoke(Object proxy, Method method, Object[] args) 的三個參數,
  1. 代理的真實對象(本文中的Ddfactory)
  2. 調用的真實方法 (saleUnknowTools)
  3. 調用的真實方法傳入的參數 (licm2.saleUnknowTools(1.2f))
  4. 一般在invoke中,會對執行方法進行增強,比如method,invoke前後加入新的方法
  1. proxy 這個類深入說一下
  1. Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods. 動態創建一個代理類對象
  2. 這個類最常用的是 public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
  1. 類加載器,由那個類加載器對象對生成的代理類進行加載,一般爲出入的實現類的接口對象(UnknowToolsFactory,一般爲factory.getclass.getclassloader)
  2. 接口的實現類 factory.getclass.getinterfaces()
  3. 爲實現invacationhandler的類
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章