<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    從靜態代理到動態代理的演變

    Posted on 2010-08-16 10:55 java小爬蟲 閱讀(1630) 評論(0)  編輯  收藏
    如上文:代理模式和裝飾者模式中的靜態代理實例,它具有如下缺陷:
        1:代理類不可重用,具有相同代理邏輯的類會大量產生;
        2:被代理方法惟一,如果有多個方法都需要相同邏輯的代理,那么代理類中就有大量的相似的方法存在;
        3:代理方法不具有參數;
        4:只實現了單接口了代理;
    所以它并不具有實戰意義上的價值!

    那么,這些問題該如何解決呢?動態代理又是一步一步如何演變過來的呢?

    下面就讓我們來一步一步以實例的方式來探究它的演變的細節。

    如果我們能動態產生一個代理類的源文件,編譯后加載到內存,那么我們就可以獲取到動態的代理對象。
    package proxy;

    import java.io.File;
    import java.io.FileWriter;
    import java.lang.reflect.Constructor;
    import java.net.URL;
    import java.net.URLClassLoader;

    import javax.tools.JavaCompiler;
    import javax.tools.StandardJavaFileManager;
    import javax.tools.ToolProvider;
    import javax.tools.JavaCompiler.CompilationTask;

    public class Proxy {
        
    public static Object newProxyInstance(Object target) throws Exception { //JDK6 Complier API, CGLib, ASM

            String rt 
    = "\r\n";
            String t 
    = "\t";
                
            String src 
    ="package proxy;"+ rt + t +    
            
    "public class TankTimeProxy implements Movable {"+ rt + t +    
            
    "private Movable obj;    "+ rt + t +    
            
    "public TankTimeProxy(Movable obj) {"+ rt + t +    
            
    "super();"+ rt + t +    
            
    "this.obj = obj;"+ rt + t +    
            
    "}"+ rt + t +    
            
    "@Override"+ rt + t +    
            
    "public void move() {"+ rt + t +    
            
    "long begintime = System.currentTimeMillis();"+ rt + t +    
            
    "System.out.println(\" Tank is begining to move !\");"+ rt + t +    
            
    "obj.move();"+ rt + t +    
            
    "long endtime = System.currentTimeMillis();"+ rt + t +    
            
    "System.out.println(\" Tank is stop !\");"+ rt + t +    
            
    "System.out.println(\"move time : \"+(endtime-begintime));"+ rt + t +    
            
    "}"+ rt + t +    
            
    "}";  
            String fileName 
    =System.getProperty("user.dir")+"/src/proxy/TankTimeProxy.java";
            File f 
    = new File(fileName);
            FileWriter fw 
    = new FileWriter(f);
            
    if(f.exists()){
                f.delete();
                fw.flush();
                f 
    = new File(fileName);
                };
            fw.write(src);
            fw.flush();
            fw.close();
            
            
    //compile
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager fileMgr 
    = compiler.getStandardFileManager(nullnullnull);
            Iterable units 
    = fileMgr.getJavaFileObjects(fileName);
            CompilationTask compilationTask 
    = compiler.getTask(null, fileMgr, nullnullnull, units);
            compilationTask.call();
            fileMgr.close();
            
            
    //load into memory and create an instance
            URL[] urls = new URL[] {new URL("file:/" + System.getProperty("user.dir")+ "/src/")};
            URLClassLoader ul 
    = new URLClassLoader(urls);
            Class c 
    = ul.loadClass("proxy.TankTimeProxy");    
                    
            Constructor ctr 
    = c.getConstructor(target.getClass().getInterfaces()[0]);
            Object m 
    = ctr.newInstance(target);
            
    return m;
        }
    }

    測試類:
    package proxy;
    public class Client {
        
    public static void main(String[] args) throws Exception{
            Movable tank 
    = (Movable)Proxy.newProxyInstance(new Tank());
            tank.move();
        }
    }




    上面的類就實現了生成TankTimeProxy.java文件,編譯,加載并被調用的功能。(全部源碼見:代理模式和裝飾者模式異同點比較

    那么怎么實現代理任意對象呢?
    在產生代理類的時候,只要動態的注入目標對象,就實現了對任意對象的代理。
    怎么實現對任意方法的代理呢?通過java反射機制,可以獲取一個類的所有方法,即可以獲取目標類的所有方法,在組成代理類java源碼的時候,循環遍歷嵌入處理邏輯就可以任意對多方法的代理了。

    示例代碼如下:

    package proxy;

    import java.io.File;
    import java.io.FileWriter;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;
    import java.net.URL;
    import java.net.URLClassLoader;

    import javax.tools.JavaCompiler;
    import javax.tools.StandardJavaFileManager;
    import javax.tools.ToolProvider;
    import javax.tools.JavaCompiler.CompilationTask;

    public class Proxy {
        
    public static Object newProxyInstance(Class intface,Object target) throws Exception //JDK6 Complier API, CGLib, ASM

            String rt 
    = "\r\n";
            String t 
    = "\t";
            String methodStr 
    = "" ;
                    
            Method[] methods 
    = intface.getDeclaredMethods();
            
    for (Method method : methods) {
                methodStr 
    += "@Override"+ rt + t +    
                
    "public void "+method.getName()+"() {"+ rt + t +    
                
    "long begintime = System.currentTimeMillis();"+ rt + t +    
                
    "System.out.println(\" Tank is begining to move !\");"+ rt + t +    
                
    "obj."+method.getName()+"();"+ rt + t +    
                
    "long endtime = System.currentTimeMillis();"+ rt + t +    
                
    "System.out.println(\" Tank is stop !\");"+ rt + t +    
                
    "System.out.println(\"move time : \"+(endtime-begintime));"+ rt + t +    
                
    "}"+ rt + t; 
            }

            
            System.out.println(methodStr);
            
            String src 
    ="package proxy;"+ rt + t +  
            
    "import "+intface.getName()+";"+ rt + t + 
            
    "public class $Proxy1 implements "+intface.getSimpleName()+" {"+ rt + t +    
            
    "private "+intface.getSimpleName()+" obj;    "+ rt + t +    
            
    "public $Proxy1("+intface.getSimpleName()+" obj) {"+ rt + t +    
            
    "super();"+ rt + t +    
            
    "this.obj = obj;"+ rt + t +    
            
    "}" + rt + t +    
            methodStr 
    +rt +
            
    "}";
             
            String fileName 
    =System.getProperty("user.dir")+"/src/proxy/$Proxy1.java";
            File f 
    = new File(fileName);
            FileWriter fw 
    = new FileWriter(f);
            
    if(f.exists()){
                f.delete();
                fw.flush();
                f 
    = new File(fileName);
                }
    ;
            fw.write(src);
            fw.flush();
            fw.close();
            
            
    //compile
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager fileMgr 
    = compiler.getStandardFileManager(nullnullnull);
            Iterable units 
    = fileMgr.getJavaFileObjects(fileName);
            CompilationTask compilationTask 
    = compiler.getTask(null, fileMgr, nullnullnull, units);
            compilationTask.call();
            fileMgr.close();
            
            
    //load into memory and create an instance
            URL[] urls = new URL[] {new URL("file:/" + System.getProperty("user.dir")+ "/src/")};
            URLClassLoader ul 
    = new URLClassLoader(urls);
            Class c 
    = ul.loadClass("proxy.$Proxy1");    
                                    
            Constructor ctr 
    = c.getConstructor(intface);
            Object m 
    = ctr.newInstance(target);
            
    return m;
        }

    }


    但是新的問題又出現了:
    在代理類中,被代理方法前后的處理邏輯已經被“寫死了”,很難改變增加的功能,這又該如何處理呢?
    我們可以這樣考慮,增加一個調用處理器InvocationHandler,把對方法的處理邏輯進行進一步的封閉,并把InvocationHandler分離出來,如果可以的話,就實現了對代理邏輯的可修改性。
    那么InvocationHandler里面應該封閉些什么東西呢?

    for (Method method : methods) {
                methodStr 
    += "@Override"+ rt + t +    
                
    "public void "+method.getName()+"() {"+ rt + t +    
                
    "long begintime = System.currentTimeMillis();"+ rt + t +    
                
    "System.out.println(\" Tank is begining to move !\");"+ rt + t +    
                
    "obj."+method.getName()+"();"+ rt + t +    
                
    "long endtime = System.currentTimeMillis();"+ rt + t +    
                
    "System.out.println(\" Tank is stop !\");"+ rt + t +    
                
    "System.out.println(\"move time : \"+(endtime-begintime));"+ rt + t +    
                
    "}"+ rt + t; 
            }
    從這個片段代理可以看出,我們應該在InvocationHandler中封裝obj對象,即被代理類的接口(實現類)。還應該實現:被分離出去的InvocationHandler能被代理類調用,我們應該把InvocationHandler聚合進來。

    代碼演變示例:
    package proxy;

    import java.lang.reflect.Method;

    public interface InvocationHandler {
        
    public void invoke(Object proxy, Method m);
    }


    package proxy;

    import java.lang.reflect.Method;

    public class TimeHandler implements InvocationHandler{
        
        
    private Object target;

        
    public TimeHandler(Object target) {
            
    this.target = target;
        }


        @Override
        
    public void invoke(Object o, Method m) {
            
    long start = System.currentTimeMillis();
            System.out.println(
    "starttime:" + start);
            System.out.println(o.getClass().getName());
            
    try {
                m.invoke(target);
            }
     catch (Exception e) {
                e.printStackTrace();
            }

            
    long end = System.currentTimeMillis();
            System.out.println(
    "time:" + (end-start));
            System.out.println(
    "endtime:" + end);
        }


    }


    package proxy;

    import java.io.File;
    import java.io.FileWriter;
    import java.lang.reflect.Constructor;

    import java.lang.reflect.Method;
    import java.net.URL;
    import java.net.URLClassLoader;

    import javax.tools.JavaCompiler;
    import javax.tools.StandardJavaFileManager;
    import javax.tools.ToolProvider;
    import javax.tools.JavaCompiler.CompilationTask;

    public class Proxy {
        
    public static Object newProxyInstance(Class intface,InvocationHandler h) throws Exception //JDK6 Complier API, CGLib, ASM

            String rt 
    = "\r\n";
            String t 
    = "\t";
            String methodStr 
    = "" ;
                    
            Method[] methods 
    = intface.getDeclaredMethods();
            
    for(Method method : methods) {
                methodStr 
    += "@Override" + rt + t + t + 
                             
    "public void " + method.getName() + "() {" + rt + t + t + t + 
                             
    "try {" + rt + t + t + t + t +  
                             
    "Method md = " + intface.getName() + ".class.getMethod(\"" + method.getName() + "\");" + rt + t + t + t + t +   
                             
    "h.invoke(this, md);" + rt + t + t + t +
                             
    "}catch(Exception e) {" + rt + t + t + t +      
                             
    "e.printStackTrace();" + rt + t + t +     
                             
    "}" + rt + t +                     
                             
    "}" + rt + t + t ;
            }

            
            System.out.println(methodStr);
            
            String src 
    ="package proxy;"+ rt + t +  
            
    "import "+intface.getName()+";"+ rt + t + 
            
    "import java.lang.reflect.Method;"+ rt + t + 
            
    "public class $Proxy1 implements "+intface.getSimpleName()+" {"+ rt + t +    
            
    "private InvocationHandler h ;    "+ rt + t +    
            
    "public $Proxy1(InvocationHandler h) {"+ rt + t +    
            
    "super();"+ rt + t +    
            
    "this.h = h;"+ rt + t +    
            
    "}" + rt + t +    
            methodStr 
    +rt +
            
    "}";
             
            String fileName 
    =System.getProperty("user.dir")+"/src/proxy/$Proxy1.java";
            File f 
    = new File(fileName);
            FileWriter fw 
    = new FileWriter(f);
            
    if(f.exists()){
                f.delete();
                fw.flush();
                f 
    = new File(fileName);
                }
    ;
            fw.write(src);
            fw.flush();
            fw.close();
            
            
    //compile
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager fileMgr 
    = compiler.getStandardFileManager(nullnullnull);
            Iterable units 
    = fileMgr.getJavaFileObjects(fileName);
            CompilationTask compilationTask 
    = compiler.getTask(null, fileMgr, nullnullnull, units);
            compilationTask.call();
            fileMgr.close();
            
            
    //load into memory and create an instance
            URL[] urls = new URL[] {new URL("file:/" + System.getProperty("user.dir")+ "/src/")};
            URLClassLoader ul 
    = new URLClassLoader(urls);
            Class c 
    = ul.loadClass("proxy.$Proxy1");    
                                    
            Constructor ctr 
    = c.getConstructor(InvocationHandler.class);
            Object m 
    = ctr.newInstance(h);
            
    return m;
        }

    }


    這樣,就實現了對任意對象,任意方法的代理。
    缺點就是:多接口代理沒有實現,被代理對象的方法沒有支持參數。

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 日日狠狠久久偷偷色综合免费| 3344免费播放观看视频| 日本高清免费中文在线看| 亚洲gay片在线gv网站| 亚洲成人激情小说| 亚洲13又紧又嫩又水多| 亚洲综合久久精品无码色欲 | 国产成人精品久久免费动漫| 中文字幕视频免费| 亚洲免费在线视频观看| 100000免费啪啪18免进| 欧美最猛性xxxxx免费| 妞干网在线免费视频| 黄a大片av永久免费| 国产精品无码免费视频二三区| 国产男女猛烈无遮挡免费视频网站 | 亚洲高清有码中文字| 亚洲精品国产av成拍色拍| 亚洲av成人无码网站…| 国产精品亚洲五月天高清| 又硬又粗又长又爽免费看| 国产一级在线免费观看| 国产精品区免费视频| 国产免费丝袜调教视频| 免费黄色app网站| 青青青国产色视频在线观看国产亚洲欧洲国产综合 | 99久久成人国产精品免费| 男人的天堂网免费网站| 免费A级毛片无码A∨免费| 成年人网站在线免费观看| 啊灬啊灬别停啊灬用力啊免费看| 久久精品国产亚洲精品| 亚洲第一精品福利| 亚洲一级毛片免观看| 无码一区二区三区亚洲人妻| 精品无码国产污污污免费网站国产| 国产成人免费AV在线播放| 久久国内免费视频| 亚洲福利中文字幕在线网址| 亚洲成在人天堂在线| 亚洲AV噜噜一区二区三区|