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

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

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

    如上文:代理模式和裝飾者模式中的靜態(tài)代理實(shí)例,它具有如下缺陷:
        1:代理類不可重用,具有相同代理邏輯的類會(huì)大量產(chǎn)生;
        2:被代理方法惟一,如果有多個(gè)方法都需要相同邏輯的代理,那么代理類中就有大量的相似的方法存在;
        3:代理方法不具有參數(shù);
        4:只實(shí)現(xiàn)了單接口了代理;
    所以它并不具有實(shí)戰(zhàn)意義上的價(jià)值!

    那么,這些問題該如何解決呢?動(dòng)態(tài)代理又是一步一步如何演變過來的呢?

    下面就讓我們來一步一步以實(shí)例的方式來探究它的演變的細(xì)節(jié)。

    如果我們能動(dòng)態(tài)產(chǎn)生一個(gè)代理類的源文件,編譯后加載到內(nèi)存,那么我們就可以獲取到動(dòng)態(tài)的代理對(duì)象。
    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;
        }
    }

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




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

    那么怎么實(shí)現(xiàn)代理任意對(duì)象呢?
    在產(chǎn)生代理類的時(shí)候,只要?jiǎng)討B(tài)的注入目標(biāo)對(duì)象,就實(shí)現(xiàn)了對(duì)任意對(duì)象的代理。
    怎么實(shí)現(xiàn)對(duì)任意方法的代理呢?通過java反射機(jī)制,可以獲取一個(gè)類的所有方法,即可以獲取目標(biāo)類的所有方法,在組成代理類java源碼的時(shí)候,循環(huán)遍歷嵌入處理邏輯就可以任意對(duì)多方法的代理了。

    示例代碼如下:

    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;
        }

    }


    但是新的問題又出現(xiàn)了:
    在代理類中,被代理方法前后的處理邏輯已經(jīng)被“寫死了”,很難改變?cè)黾拥墓δ埽@又該如何處理呢?
    我們可以這樣考慮,增加一個(gè)調(diào)用處理器InvocationHandler,把對(duì)方法的處理邏輯進(jìn)行進(jìn)一步的封閉,并把InvocationHandler分離出來,如果可以的話,就實(shí)現(xiàn)了對(duì)代理邏輯的可修改性。
    那么InvocationHandler里面應(yīng)該封閉些什么東西呢?

    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; 
            }
    從這個(gè)片段代理可以看出,我們應(yīng)該在InvocationHandler中封裝obj對(duì)象,即被代理類的接口(實(shí)現(xiàn)類)。還應(yīng)該實(shí)現(xiàn):被分離出去的InvocationHandler能被代理類調(diào)用,我們應(yīng)該把InvocationHandler聚合進(jìn)來。

    代碼演變示例:
    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;
        }

    }


    這樣,就實(shí)現(xiàn)了對(duì)任意對(duì)象,任意方法的代理。
    缺點(diǎn)就是:多接口代理沒有實(shí)現(xiàn),被代理對(duì)象的方法沒有支持參數(shù)。

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 无码专区永久免费AV网站| 久久精品私人影院免费看| 一个人看的hd免费视频| a级成人毛片免费图片| jjizz全部免费看片| 天天天欲色欲色WWW免费| 亚洲人成人无码网www国产| 亚洲国产精品无码专区| 亚洲综合色7777情网站777| 国产精品国产亚洲区艳妇糸列短篇 | 亚洲va中文字幕| 人人爽人人爽人人片av免费| 免费黄网站在线看| 美女视频黄的全免费视频| 免费一级国产生活片| 久久精品国产精品亚洲艾| 亚洲综合av一区二区三区| 一个人看的www视频免费在线观看 一个人看的免费观看日本视频www | 一级毛片免费视频| 免费黄色app网站| 亚洲人精品午夜射精日韩| 亚洲H在线播放在线观看H| 又粗又长又爽又长黄免费视频| 97青青草原国产免费观看| 国产免费观看黄AV片| 亚洲av色福利天堂| MM1313亚洲国产精品| 久久综合九色综合97免费下载| 国产精品无码一区二区三区免费| 亚洲αv在线精品糸列| 国产AV无码专区亚洲AV蜜芽| 午夜网站在线观看免费完整高清观看| 成人毛片视频免费网站观看| 亚洲国产a∨无码中文777| 亚洲国产成人久久精品软件 | 我想看一级毛片免费的| 亚洲精品美女久久久久99| 亚洲精品无AMM毛片| 久久久久国色av免费看| 免费人妻av无码专区| 亚洲AV无码精品蜜桃|