動態代理的實現

一.我對動態代理的理解

1.動態生成代理類java源文件
2.將代理類java源文件編譯為代理類class字節碼文件
3.將代理類class字節碼文件 自動加載到內存中
4.將自動加載到內存的代理類class字節碼進行實例化為 代理對象
5.有了代理對象,就可以使用代理對象中的方法調用被代理對象的方法了;

二.動態代理的實現流程

點擊查看代碼演示

1.編寫接口MoveAble 有move方法

package proxy.statics;
/**
 * 移動接口
 * @author lxf
 *
 */
public interface MoveAble {
    public  void move();
}

2.編寫被代理類Car實現MoveAble接口,并實現move方法寫業務羅輯;

package proxy.statics;
import java.util.Random;
/**
 * 被代理類,汽車
 * @author lxf
 * @2017-07-06
 */
public class Car implements MoveAble {

    @Override
    public void move() {
        //System.out.println("被代理對象---我是汽車對象本身:"+this.getClass().getName());
       //實現開車
       try {
            Thread.sleep(new Random().nextInt(1000));
            System.out.println("汽車行駛中...");
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

3.編寫InvocationHandler接口(包含myinvoke方法)
注意:這里的InvocationHandler并不是java.lang.refect包下面的InvocationHandler

package proxy.dynamic.custom;
import java.lang.reflect.Method;
/**
 * 事務處理接口
 * @author lxf
 *
 */
public interface InvocationHandler {
    /**
     * 參數:Object obj 屬于代理對象
     * 參數:Method method 屬于代理對象的方法
     */
    public void myinvoke(Object obj, Method method);
}

4.編寫TimerHandler類實現自己InvocationHandler接口中的myinvoke方法(用來調用被代理對象的方法,還有其他額外的業務邏輯)

package proxy.dynamic.custom;
import java.lang.reflect.Method;
/**
 * 實現自己定義的事務處理接口proxy.dynamic.custom.InvocationHandler
 * @author lxf
 *
 */
public class TimerHandler implements  InvocationHandler {
    //代理對象
    private Object target;
   
    public TimerHandler(Object target) {
        super();
        this.target = target;
    }

    /**
     * 參數:Object obj 屬于代理對象
     * 參數:Method method 屬于代理對象的方法
     */
    @Override
    public void myinvoke(Object obj, Method method) {
        // TODO Auto-generated method stub
        try {
            //開始時間 " + br + 
            Long start = System.currentTimeMillis(); 
            System.out.println("汽車開始行駛...");
            method.invoke(target);
            //結束時間 " + br + 
            Long end = System.currentTimeMillis(); 
            System.out.println("汽車結束行駛...行駛話費了:" + (end-start) + "ms"); 
            //視頻聽到3-3 3:42秒
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
    }
}

3.編寫生成代理類的類Proxy,它的主要功能是 一步驟 中的所有流程;

package proxy.dynamic.custom;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import org.apache.commons.io.FileUtils;
import javax.tools.JavaCompiler.CompilationTask;
import proxy.statics.Car;
import proxy.statics.MoveAble;
/**
 * 動態代理類
 * @author lxf
 * 參數:
 * Class 代理類和被代理類實現的接口
 *  InvocationHandler h 自己實現的事務處理器proxy.dynamic.custom.TimerHandler
 *
 */
public class Proxy {
    
    /**
     * 自己實現JDK生成動態代理類及對象
     * @param infce 接口class,有了接口就可以通過接口獲取接口中定義的方法,為生成代理類而用
     * @param h 自己創建的proxy.dynamic.custom.InvocationHandler 事務處理器(處理主要業務羅輯)
     *       事務處理器中包含被代理對象Car,具體處理業務羅輯的代碼
     * @return
     * @throws IOException
     */
    public static Object newProxyInstance(Class infce, InvocationHandler h) throws IOException
    {
        String br = "\n"; //換行符
        String methodStr = "";
        //獲取接口中所有的方法,遍歷組合為代理類的方法
        for(Method m : infce.getMethods()){
            methodStr += "  @Override" + br +
            "   public void " + m.getName() + "() {" + br +
            "  try{" + br +
            "  Method md = " + infce.getName() + ".class.getMethod(\"" 
                                        + m.getName() + "\");" + br +
            "  h.myinvoke(this,md);" +br+ 
            "  }catch(Exception e){ e.printStackTrace();}" + br +
            "   }" ;
        }
        
        /**
         * 動態代理類字符串
         */
        String str = 
        " package proxy.dynamic.custom; " + br + 
        " import proxy.dynamic.custom.InvocationHandler; " + br +
        "  import java.lang.reflect.Method;" + br +
        " public class $Proxy0  implements "+infce.getName()+"{ " + br + 
         "  private InvocationHandler h; " + br + 
         "   public $Proxy0( InvocationHandler h ) " + br + 
         "  { " + br + 
         "       this.h = h; " + br + 
         "  } " + br +
         methodStr + br +
        "}";
        
        /*
         * 自行實現動態代理的流程
         * 1. 動態生成代理類.java源文件
         */
        //獲取當前項目路徑,/home/lxf/workspaceEE/proxy
        String filename = System.getProperty("user.dir") + "/bin/proxy/dynamic/custom/$Proxy0.java";
        System.out.println(filename);
        File file = new File(filename);
        FileUtils.writeStringToFile(file, str);
        
        /*
         * 2. 將動態生成的代理類.java源文件編譯為class字節碼文件
         */
        //編譯
        //拿到編譯器
        JavaCompiler complier = ToolProvider.getSystemJavaCompiler();
        //文件管理者
        StandardJavaFileManager fileMgr = 
                complier.getStandardFileManager(null, null, null);
        //獲取文件
        Iterable units = fileMgr.getJavaFileObjects(filename);
        //編譯任務
        CompilationTask t = complier.getTask(null, fileMgr, null, null, null, units);
        //進行編譯
        t.call();
        fileMgr.close();
           
       /**
        * load到內存中
        */
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        Class c;
        try {
            c = cl.loadClass("proxy.dynamic.custom.$Proxy0");
            //System.out.println(c.getName());
            //通過構造器返回代理對象
            Constructor ctr = c.getConstructor(InvocationHandler.class);
            return ctr.newInstance(h);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       return null;
    }
}

4.測試

package proxy.dynamic.custom;
import java.io.IOException;
import proxy.statics.Car;
import proxy.statics.MoveAble;
/**
 * 測試自己實現JDK動態代理實現思路
 * @author lxf
 * @date 2017-07-07
 */
public class testMain {
    public static void main(String[] args) throws IOException
    {
        //實例化被代理類
        Car car = new Car();
        //實例化事務處理器
        InvocationHandler h = new TimerHandler(car);
        //生成代理對象
        MoveAble m = (MoveAble)Proxy.newProxyInstance(MoveAble.class,h);
        //調用代理對象的方法
        m.move();
    }    
}

執行結果:

/home/lxf/workspaceEE/proxy/bin/proxy/dynamic/custom/$Proxy0.java
汽車開始行駛...
汽車行駛中...
汽車結束行駛...行駛話費了:975ms

動態生成代理類/home/lxf/workspaceEE/proxy/bin/proxy/dynamic/custom/$Proxy0.java的代碼如下:

 package proxy.dynamic.custom; 
 import proxy.dynamic.custom.InvocationHandler; 
  import java.lang.reflect.Method;
 public class $Proxy0  implements proxy.statics.MoveAble{ 
  private InvocationHandler h; 
   public $Proxy0( InvocationHandler h ) 
  { 
       this.h = h; 
  } 
  @Override
   public void move() {
  try{
  Method md = proxy.statics.MoveAble.class.getMethod("move");
  h.myinvoke(this,md);
  }catch(Exception e){ e.printStackTrace();}
   }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容