面向?qū)ο缶幊淘O(shè)計(jì)模式------代理模式(靜態(tài)代理、動(dòng)態(tài)代理)

代理模式

??代理模式的定義:給某一個(gè)對(duì)象提供一個(gè)代理,并由代理對(duì)象控制對(duì)原對(duì)象的引用。
??代理(Proxy)是一種設(shè)計(jì)模式,提供了對(duì)目標(biāo)對(duì)象另外的訪問(wèn)方式;即通過(guò)代理對(duì)象訪問(wèn)目標(biāo)對(duì)象。這樣做的好處是:可以在目標(biāo)對(duì)象實(shí)現(xiàn)的基礎(chǔ)上,增強(qiáng)額外的功能操作,即擴(kuò)展目標(biāo)對(duì)象的功能。
??這里使用到編程中的一個(gè)思想:不要隨意去修改別人已經(jīng)寫好的代碼或者方法,如果需改修改,可以通過(guò)代理的方式來(lái)擴(kuò)展該方法。
??舉個(gè)例子來(lái)說(shuō)明代理的作用:假設(shè)我們想邀請(qǐng)一位明星,那么并不是直接聯(lián)系明星,而是聯(lián)系明星的經(jīng)紀(jì)人,來(lái)達(dá)到同樣的目的。明星就是一個(gè)目標(biāo)對(duì)象,他只要負(fù)責(zé)活動(dòng)中的節(jié)目,而其他瑣碎的事情就交給他的代理人(經(jīng)紀(jì)人)來(lái)解決。這就是代理思想在現(xiàn)實(shí)中的一個(gè)例子。

??代理模式的關(guān)鍵點(diǎn)是:代理對(duì)象與目標(biāo)對(duì)象。代理對(duì)象是對(duì)目標(biāo)對(duì)象的擴(kuò)展,并會(huì)調(diào)用目標(biāo)對(duì)象。
??代理模式包含如下角色:
??ISubject:抽象主題角色,是一個(gè)接口。該接口是對(duì)象和它的代理共用的接口。
??RealSubject:真實(shí)主題角色,是實(shí)現(xiàn)抽象主題接口的類。
??Proxy:代理角色,內(nèi)部含有對(duì)真實(shí)對(duì)象RealSubject的引用,從而可以操作真實(shí)對(duì)象。代理對(duì)象提供與真實(shí)對(duì)象相同的接口,以便在任何時(shí)刻都能代替真實(shí)對(duì)象。同時(shí),代理對(duì)象可以在執(zhí)行真實(shí)對(duì)象操作時(shí),附加其他的操作,相當(dāng)于對(duì)真實(shí)對(duì)象進(jìn)行封裝。
??代理模式的應(yīng)用:
??遠(yuǎn)程代理:也就是為一個(gè)對(duì)象在不同的地址空間提供局部代表。這樣可以隱藏一個(gè)對(duì)象存在于不同地址空間的事實(shí)。
??虛擬代理:是根據(jù)需要?jiǎng)?chuàng)建開銷很大的對(duì)象。通過(guò)它來(lái)存放實(shí)例化需要很長(zhǎng)時(shí)間的真實(shí)對(duì)象。
??安全代理:用來(lái)控制真實(shí)對(duì)象訪問(wèn)時(shí)的權(quán)限。
??智能代理:是指當(dāng)調(diào)用真實(shí)的對(duì)象時(shí),代理處理一些另外的事情。
??一般將代理分類的話,可分為靜態(tài)代理和動(dòng)態(tài)代理兩種。

靜態(tài)代理

??靜態(tài)代理比較簡(jiǎn)單,是由程序員編寫的代理類,并在程序運(yùn)行前就編譯好的,而不是由程序動(dòng)態(tài)產(chǎn)生代理類,這就是所謂的靜態(tài)。
??考慮這樣的場(chǎng)景,管理員在網(wǎng)站上執(zhí)行操作,在生成操作結(jié)果的同時(shí)需要記錄操作日志,這是很常見的。此時(shí)就可以使用代理模式,代理模式可以通過(guò)聚合和繼承兩種方式實(shí)現(xiàn):

/**
 * @Description: 抽象主題接口
 * @author: zxt
 * @time: 2018年7月7日 下午2:29:46
 */
public interface Manager {
    public void doSomething();
}

/**
 * @Description: 真實(shí)的主題類
 * @author: zxt
 * @time: 2018年7月7日 下午2:31:21
 */
public class Admin implements Manager {
    @Override
    public void doSomething() {
        System.out.println("這是真實(shí)的主題類:Admin doSomething!!!");
    }
}

/**
 * @Description: 以聚合的方式實(shí)現(xiàn)代理主題
 * @author: zxt
 * @time: 2018年7月7日 下午2:37:08
 */
public class AdminPoly implements Manager {
    // 真實(shí)主題類的引用
    private Admin admin;
    
    public AdminPoly(Admin admin) {
        this.admin = admin;
    }
    
    @Override
    public void doSomething() {
        System.out.println("聚合方式實(shí)現(xiàn)代理:Admin操作開始?。?);
        admin.doSomething();
        System.out.println("聚合方式實(shí)現(xiàn)代理:Admin操作結(jié)束?。?);
    }
}

/**
 * @Description: 繼承方式實(shí)現(xiàn)代理
 * @author: zxt
 * @time: 2018年7月7日 下午2:40:39
 */
public class AdminProxy extends Admin {
    @Override
    public void doSomething() {
        System.out.println("繼承方式實(shí)現(xiàn)代理:Admin操作開始??!");
        super.doSomething();
        System.out.println("繼承方式實(shí)現(xiàn)代理:Admin操作結(jié)束??!");
    }
}

public static void main(String[] args) {
    // 1、聚合方式的測(cè)試
    Admin admin = new Admin();
    Manager manager = new AdminPoly(admin);
    manager.doSomething();
    
    System.out.println("============================");
    // 2、繼承方式的測(cè)試
    AdminProxy proxy = new AdminProxy();
    proxy.doSomething();
}

??聚合實(shí)現(xiàn)方式中代理類聚合了被代理類,且代理類及被代理類都實(shí)現(xiàn)了同一個(gè)接口,可實(shí)現(xiàn)靈活多變。繼承式的實(shí)現(xiàn)方式則不夠靈活。
??比如,在管理員操作的同時(shí)需要進(jìn)行權(quán)限的處理,操作內(nèi)容的日志記錄,操作后數(shù)據(jù)的變化三個(gè)功能。三個(gè)功能的排列組合有6種,也就是說(shuō)使用繼承要編寫6個(gè)繼承了Admin的代理類,而使用聚合,僅需要針對(duì)權(quán)限的處理、日志記錄和數(shù)據(jù)變化三個(gè)功能編寫代理類,在業(yè)務(wù)邏輯中根據(jù)具體需求改變代碼順序即可。
??缺點(diǎn):
??1)、代理類和委托類實(shí)現(xiàn)了相同的接口,代理類通過(guò)委托類實(shí)現(xiàn)了相同的方法。這樣就出現(xiàn)了大量的代碼重復(fù)。如果接口增加一個(gè)方法,除了所有實(shí)現(xiàn)類需要實(shí)現(xiàn)這個(gè)方法外,所有代理類也需要實(shí)現(xiàn)此方法。增加了代碼維護(hù)的復(fù)雜度。
??2)、代理對(duì)象只服務(wù)于一種類型的對(duì)象,如果要服務(wù)多類型的對(duì)象。勢(shì)必要為每一種對(duì)象都進(jìn)行代理,靜態(tài)代理在程序規(guī)模稍大時(shí)就無(wú)法勝任了。

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

??實(shí)現(xiàn)動(dòng)態(tài)代理的關(guān)鍵技術(shù)是反射。
??一般來(lái)說(shuō),對(duì)代理模式而言,一個(gè)主題類與一個(gè)代理類一一對(duì)應(yīng),這也是靜態(tài)代理模式的特點(diǎn)。
??但是,也存在這樣的情況,有n各主題類,但是代理類中的“前處理、后處理”都是一樣的,僅調(diào)用主題不同。也就是說(shuō),多個(gè)主題類對(duì)應(yīng)一個(gè)代理類,共享“前處理,后處理”功能,動(dòng)態(tài)調(diào)用所需主題,大大減小了程序規(guī)模,這就是動(dòng)態(tài)代理模式的特點(diǎn)。動(dòng)態(tài)代理主要有兩種:JDK自帶的動(dòng)態(tài)代理和CGLIB動(dòng)態(tài)代理。
??首先是另一個(gè)靜態(tài)代理的實(shí)例:

1、一個(gè)可移動(dòng)接口

public interface Moveable {
    
    public void move();
}

2、一個(gè)實(shí)現(xiàn)了該接口的Car類

public class Car implements Moveable {

    @Override
    public void move() {
        try {
            Thread.sleep(new Random().nextInt(1000));
            System.out.println("汽車行駛中----");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

3、現(xiàn)在需要有一個(gè)代理類來(lái)記錄Car的運(yùn)行時(shí)間:

public class CarTimeProxy implements Moveable {
    private Moveable m;
    
    public CarTimeProxy(Moveable m) {
        super();
        this.m = m;
    }

    @Override
    public void move() {
        long startTime = System.currentTimeMillis();
        System.out.println("汽車行駛前----");
        m.move();
        long endTime = System.currentTimeMillis();
        System.out.println("汽車行駛結(jié)束----行駛時(shí)間為:" + (endTime - startTime) + "毫秒!");
    }
}

4、另一個(gè)代理類記錄Car的日志:

public class CarLogProxy implements Moveable {
    private Moveable m;
    
    public CarLogProxy(Moveable m) {
        super();
        this.m = m;
    }

    @Override
    public void move() {
        System.out.println("日志開始");
        m.move();
        System.out.println("日志結(jié)束");
    }
}

5、客戶端的調(diào)用:

public class CarTest {

    public static void main(String[] args) {
        Car car = new Car();
        // 先寫日志,再計(jì)時(shí)
        CarTimeProxy ctp = new CarTimeProxy(car);
        CarLogProxy clp = new CarLogProxy(ctp);
        clp.move();
        
        System.out.println();
        // 先計(jì)時(shí),再寫日志
        CarLogProxy clp1 = new CarLogProxy(car);
        CarTimeProxy ctp1 = new CarTimeProxy(clp1);
        ctp1.move();
    }
}



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

在java的動(dòng)態(tài)代理機(jī)制中,有兩個(gè)重要的類或接口,一個(gè)是InvocationHandler(Interface)、另一個(gè)則是 Proxy(Class),這一個(gè)類和接口是實(shí)現(xiàn)我們動(dòng)態(tài)代理所必須用到的。




??JDK動(dòng)態(tài)代理的實(shí)現(xiàn)
??1、創(chuàng)建一個(gè)實(shí)現(xiàn)接口InvocationHandler的類,它必須實(shí)現(xiàn)invoke方法。
??使用JDK動(dòng)態(tài)代理類時(shí),需要實(shí)現(xiàn)InvocationHandler接口,所有動(dòng)態(tài)代理類的方法調(diào)用,都會(huì)交由InvocationHandler接口實(shí)現(xiàn)類里的invoke()方法去處理。這是動(dòng)態(tài)代理的關(guān)鍵所在。
??2、創(chuàng)建被代理的類以及接口。
??3、調(diào)用Proxy的靜態(tài)方法,創(chuàng)建代理類。
??newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h);
??4、通過(guò)代理調(diào)用方法。
??使用JDK動(dòng)態(tài)代理的方式實(shí)現(xiàn)上面Car的時(shí)間代理:

1、首先是InvocationHandler接口的實(shí)現(xiàn)類:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class TimeHandler implements InvocationHandler {
    // 被傳遞過(guò)來(lái)的要被代理的對(duì)象
    private Object object;
    
    public TimeHandler(Object object) {
        super();
        this.object = object;
    }

    /**
     * proxy:被代理的對(duì)象
     * method:被代理的方法
     * args:被代理方法的參數(shù)
     * 
     * 函數(shù)返回:method的返回
     * 
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long startTime = System.currentTimeMillis();
        System.out.println("汽車行駛前----");
        method.invoke(object, args);
        long endTime = System.currentTimeMillis();
        System.out.println("汽車行駛結(jié)束----行駛時(shí)間為:" + (endTime - startTime) + "毫秒!");
        return null;
    }
}

2、創(chuàng)建動(dòng)態(tài)代理類:

/**
 * @Description: JDK動(dòng)態(tài)代理的測(cè)試類
 * @author: zxt
 * @time: 2019年3月1日 下午7:59:29
 */
public class TimeHandlerTest {

    public static void main(String[] args) {
        // 需要被代理的對(duì)象
        Car car = new Car();
        InvocationHandler h = new TimeHandler(car);
        
        Class<?> clazz = car.getClass();
        
        /**
         * 參數(shù)一:類加載器
         * 參數(shù)二:被代理類實(shí)現(xiàn)的接口
         * 參數(shù)三:InvocationHandler實(shí)例
         * 
         * 函數(shù)返回:返回由InvocationHandler接口接收的被代理類的一個(gè)動(dòng)態(tài)代理類對(duì)象
         */
        Moveable m = (Moveable) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), h);
        m.move();
    }
}


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

??JDK動(dòng)態(tài)代理可以在運(yùn)行時(shí)動(dòng)態(tài)生成字節(jié)碼,主要使用到了一個(gè)接口InvocationHandler與Proxy.newProxyInstance靜態(tài)方法。使用內(nèi)置的Proxy實(shí)現(xiàn)動(dòng)態(tài)代理有一個(gè)問(wèn)題:被代理的類必須要實(shí)現(xiàn)某接口,未實(shí)現(xiàn)接口則沒辦法完成動(dòng)態(tài)代理。
??如果項(xiàng)目中有些類沒有實(shí)現(xiàn)接口,則不應(yīng)該為了實(shí)現(xiàn)動(dòng)態(tài)代理而刻意去抽象出一些沒有實(shí)際意義的接口,通過(guò)cglib可以解決該問(wèn)題。
??CGLIB(Code Generation Library)是一個(gè)開源項(xiàng)目,是一個(gè)強(qiáng)大的,高性能,高質(zhì)量的Code生成類庫(kù),它可以在運(yùn)行期擴(kuò)展Java類與實(shí)現(xiàn)Java接口,通俗地說(shuō)cglib可以在運(yùn)行時(shí)動(dòng)態(tài)生成字節(jié)碼。
??使用cglib完成動(dòng)態(tài)代理,大概的原理是:cglib繼承被代理的類,重寫方法,織入通知,動(dòng)態(tài)生成字節(jié)碼并運(yùn)行。對(duì)指定目標(biāo)類產(chǎn)生一個(gè)子類,通過(guò)方法攔截技術(shù)攔截所有父類的方法調(diào)用,因?yàn)槭抢^承實(shí)現(xiàn)所以final類是沒有辦法動(dòng)態(tài)代理的。

CGLIB動(dòng)態(tài)代理實(shí)例:

import java.util.Random;

// 不實(shí)現(xiàn)接口的被代理類
public class Train {
    
    public void move() {
        try {
            Thread.sleep(new Random().nextInt(1000));
            System.out.println("火車行駛中----");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibProxy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();
    
    // 得到代理類的方法
    public Object getProxy(Class<?> clazz) {
        // 設(shè)置創(chuàng)建子類的類  (即我們需要為哪個(gè)類產(chǎn)生代理類)
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        
        return enhancer.create();
    }
    
    /**
     * 攔截所有目標(biāo)類方法的調(diào)用
     * 
     * object:目標(biāo)類的實(shí)例
     * method:目標(biāo)類的目標(biāo)方法的反射實(shí)例
     * args:目標(biāo)方法的參數(shù)
     * proxy:代理類的實(shí)例
     */
    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        long startTime = System.currentTimeMillis();
        System.out.println("火車行駛前----");
        
        // 代理類調(diào)用父類的方法 (由于Cglib動(dòng)態(tài)代理的實(shí)現(xiàn)是通過(guò)繼承被代理類,因此代理類這里需要調(diào)用父類的方法)
        proxy.invokeSuper(object, args);
        
        long endTime = System.currentTimeMillis();
        System.out.println("火車行駛結(jié)束----行駛時(shí)間為:" + (endTime - startTime) + "毫秒!");
        return null;
    }
}
public class CglibProxyTest {
    
    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();
        Train train = (Train) cglibProxy.getProxy(Train.class);
        train.move();
    }
}


JDK動(dòng)態(tài)代理的模擬實(shí)現(xiàn)

模擬JDK動(dòng)態(tài)代理的實(shí)現(xiàn),根據(jù)Java源代碼動(dòng)態(tài)生成代理類。

package com.zxt.jdkproxy;

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

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

import org.apache.commons.io.FileUtils;

import com.zxt.staticproxy.Car;

/**
 * 
 * @Description: 模擬JDK動(dòng)態(tài)代理的實(shí)現(xiàn)
 * 動(dòng)態(tài)代理的實(shí)現(xiàn)思路:
 * 實(shí)現(xiàn)功能:通過(guò)自定義的Proxy的newProxyInstance方法返回代理對(duì)象
 * 1、聲明一段源碼(動(dòng)態(tài)產(chǎn)生代理)
 * 2、編譯源碼(JDK Compiler API),產(chǎn)生新的類(代理類)
 * 3、將這個(gè)類load到內(nèi)存當(dāng)中,產(chǎn)生一個(gè)新的對(duì)象(代理對(duì)象)
 * 4、return 代理對(duì)象
 *
 * @author: zxt
 *
 * @time: 2019年4月18日 下午3:44:58
 *
 */
public class MyProxy {
    
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static Object newProxyInstance(Class<?> inteface) throws Exception {
        // 1、聲明一段源碼(動(dòng)態(tài)產(chǎn)生代理)
        String rt = "\r\n";
        String methodStr = "";
        for(Method m : inteface.getMethods()) {
            methodStr += "  @Override" + rt
                       + "  public void " + m.getName() + "() {" + rt
                       + "      System.out.println(\"日志開始\");" + rt
                       + "      m." + m.getName() + "();" + rt
                       + "      System.out.println(\"日志結(jié)束\");" + rt
                       + "  }";
        }
        String code = 
            "package com.zxt.jdkproxy;" + rt + "\n"
            + "import com.zxt.staticproxy.Moveable;" + rt + "\n"
            + "public class $MyProxy0 implements " + inteface.getSimpleName() + " {" + rt + "\n"
            + " private " + inteface.getSimpleName() + " m;" + rt + "\n"
            + " public $MyProxy0(" + inteface.getSimpleName() + " m) {" + rt
            + "     super();" + rt
            + "     this.m = m;" + rt
            + " }" + rt + "\n"
            + methodStr + rt + "\n"
            + "}";
        
        
        // 由源代碼生成java類文件
        String filename = System.getProperty("user.dir") + "/bin/com/zxt/jdkproxy/$MyProxy0.java";
        File file = new File(filename);
        // 使用commons-io里面的簡(jiǎn)便的工具類來(lái)寫文件
        FileUtils.writeStringToFile(file, code, "UTF-8");
        
        
        // 2、編譯源碼(JDK Compiler API),產(chǎn)生新的類(代理類)
        // 拿到編譯器
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        // 文件管理者
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
        // 獲取文件
        Iterable units = fileManager.getJavaFileObjects(filename);
        // 獲取編譯任務(wù)
        CompilationTask task = compiler.getTask(null, fileManager, null, null, null, units);
        // 編譯
        task.call();
        fileManager.close();
        
        // 3、加載到內(nèi)存
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        Class c = cl.loadClass("com.zxt.jdkproxy.$MyProxy0");
        
        // 4、返回代理類
        Constructor ctr = c.getConstructor(inteface);
        return ctr.newInstance(new Car());
    }
    
    
    public static void main(String[] args) {

    }
}
public class MyProxyTest {
    public static void main(String[] args) throws Exception {
        Moveable m = (Moveable) MyProxy.newProxyInstance(Moveable.class);
        m.move();
    }
}

??可以發(fā)現(xiàn)上述實(shí)現(xiàn)中的源代碼是寫死在類中的,因此無(wú)法對(duì)任意類進(jìn)行動(dòng)態(tài)代理,所以仿照InvocationHandler接口,定義自己的InvocationHandler接口從而實(shí)現(xiàn)對(duì)不同的類進(jìn)行動(dòng)態(tài)代理。

import java.lang.reflect.Method;

public interface MyInvocationHandler {

    public void invoke(Object o, Method m);
}

實(shí)現(xiàn)該接口的類

import java.lang.reflect.Method;

public class MyLogHandler implements MyInvocationHandler {
    // 需要被代理的對(duì)象
    private Object target;

    public MyLogHandler(Object target) {
        super();
        this.target = target;
    }

    @Override
    public void invoke(Object o, Method m) {
        try {
            System.out.println("日志開始");
            m.invoke(target);
            System.out.println("日志結(jié)束");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

對(duì)動(dòng)態(tài)代理MyProxy類進(jìn)行改進(jìn)

/**
 * 
 * @Description: 模擬JDK動(dòng)態(tài)代理的實(shí)現(xiàn)
 * 動(dòng)態(tài)代理的實(shí)現(xiàn)思路:
 * 實(shí)現(xiàn)功能:通過(guò)自定義的Proxy的newProxyInstance方法返回代理對(duì)象
 * 1、聲明一段源碼(動(dòng)態(tài)產(chǎn)生代理)
 * 2、編譯源碼(JDK Compiler API),產(chǎn)生新的類(代理類)
 * 3、將這個(gè)類load到內(nèi)存當(dāng)中,產(chǎn)生一個(gè)新的對(duì)象(代理對(duì)象)
 * 4、return 代理對(duì)象
 *
 * @author: zxt
 *
 * @time: 2019年4月18日 下午3:44:58
 *
 */
public class MyProxy {
    
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static Object newProxyInstance(Class<?> inteface, MyInvocationHandler h) throws Exception {
        // 1、聲明一段源碼(動(dòng)態(tài)產(chǎn)生代理)
        String rt = "\r\n";
        String methodStr = "";
        for(Method m : inteface.getMethods()) {
            methodStr += "  @Override" + rt
                       + "  public void " + m.getName() + "() {" + rt
                       + "      try { " + rt
                       + "          Method md = " + inteface.getSimpleName() + ".class.getMethod(\""
                                              + m.getName() + "\");" + rt
                       + "          h.invoke(this, md);" + rt
                       + "      } catch (Exception e) { " + rt
                       + "          e.printStackTrace();" + rt
                       + "      }" + rt
                       + "  }";
        }
        String code = 
            "package com.zxt.jdkproxy;" + rt + "\n"
            + "import java.lang.reflect.Method;" + rt
            + "import com.zxt.staticproxy.Moveable;" + rt + "\n"
            + "public class $MyProxy0 implements " + inteface.getSimpleName() + " {" + rt + "\n"
            + " private MyInvocationHandler h;" + rt + "\n"
            + " public $MyProxy0( MyInvocationHandler h ) {" + rt
            + "     this.h = h;" + rt
            + " }" + rt + "\n"
            + methodStr + rt + "\n"
            + "}";
        
        
        // 由源代碼生成java類文件
        String filename = System.getProperty("user.dir") + "/bin/com/zxt/jdkproxy/$MyProxy0.java";
        File file = new File(filename);
        // 使用commons-io里面的簡(jiǎn)便的工具類來(lái)寫文件
        FileUtils.writeStringToFile(file, code, "UTF-8");
        
        
        // 2、編譯源碼(JDK Compiler API),產(chǎn)生新的類(代理類)
        // 拿到編譯器
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        // 文件管理者
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
        // 獲取文件
        Iterable units = fileManager.getJavaFileObjects(filename);
        // 獲取編譯任務(wù)
        CompilationTask task = compiler.getTask(null, fileManager, null, null, null, units);
        // 編譯
        task.call();
        fileManager.close();
        
        // 3、加載到內(nèi)存
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        Class c = cl.loadClass("com.zxt.jdkproxy.$MyProxy0");
        
        // 4、返回代理類
        Constructor ctr = c.getConstructor(MyInvocationHandler.class);
        return ctr.newInstance(h);
    }
}

測(cè)試類:

public class MyProxyTest {
    
    public static void main(String[] args) throws Exception {
        // 需要被代理的對(duì)象
        Car car = new Car();
        MyInvocationHandler h = new MyLogHandler(car);

        Moveable m = (Moveable) MyProxy.newProxyInstance(Moveable.class, h);
        m.move();
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容