什么是java代理

什么是java代理

代理是設(shè)計模式的一種,其原理就是通過代理對象去訪問目標對象,而外部只能訪問到代理對象

在編程中有這么一種思想,你不要隨便的去修改已經(jīng)寫好的代碼,如需修改,那么可以通過代理來擴展類的功能。

<a name="z7z8I"></a>

靜態(tài)代理

什么是靜態(tài)代理,靜態(tài)代理就是你定義一個接口或者是父類,然后代理類與被代理類都需要繼承這個接口,在代理類中實現(xiàn)一個方法,需要注入被代理類,這樣就能通過代理類去訪問被代理類,同時,也可以對被代理類進行增強。

上代碼:

/**
 * 定義一個接口,包含一個方法,吃
 */
public interface Person {

    void eat();
}
/**
 * 實現(xiàn) Person
 * 這個是一個實際的目標類,當前類實現(xiàn)一個吃的方法
 */
public class Man implements Person {
    public void eat() {
        System.out.println("吃飯");
    }
}

/**
 * Man對象的代理,當前代理持有一個Man的對象
 */
public class ManProxy implements Person {

    private Person target;
    public ManProxy(Person target){
        this.target = target;
    }
    public void eat() {
        System.out.println("吃冷菜");
        target.eat();
        System.out.println("吃甜品");
    }
}

/**
 * 測試
 */
public class App {
    public static void main(String[] args) {
        Person target = new Man();
        Person manProxy = new ManProxy(target);
        manProxy.eat();
    }
}

結(jié)果:

吃冷菜
吃飯
吃甜品

以上就是一個典型的靜態(tài)代理的例子,在當前的例子里,有一個Person的接口,該接口的主要作用是定義一個代理類和被代理類都擁有的行為,當前的行為為eat

代理類和被代理類都實現(xiàn)了Person,不過不同的是,代理類持有了一個被代理類的對象,在代理類中可以執(zhí)行被代理類的方法,因此在代理類中可以在該方法的基礎(chǔ)上進行擴展。

缺點:由于代理類需要實現(xiàn)與被代理類同一個接口,那么不同的被代理類就需要去實現(xiàn)不同的接口,那么就會出現(xiàn)代理類很難復(fù)用的情況,相對的維護成本也難以控制。

<a name="ZeuqT"></a>

動態(tài)代理

什么是動態(tài)代理,動態(tài)代理就是利用JDK的API動態(tài)的在內(nèi)存中構(gòu)建代理對象,因此,動態(tài)代理也叫做JDK代理,或者接口代理,在動態(tài)代理中,代理對象不需要實現(xiàn)接口,但是被代理對象還是需要實現(xiàn)對象的。

<a name="88hpa"></a>

生成代理對象的API

生成代理對象的API主要的包在java.lang.reflect.Proxy

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )

參數(shù)說明:<br />ClassLoader loader : 該參數(shù)是被代理對象的使用的類加載器,這個我們直接通過被代理對象就可以獲取

Class<?>[] interfaces : 被代理對象實現(xiàn)的接口,這個也可以通過被代理對象獲取

InvocationHandler h : 當我們在執(zhí)行被代理對象的方法的時候,這個處理器就會被執(zhí)行,當這個方法被執(zhí)行的時候,會將被代理對象,方法,參數(shù)都傳入進去

上代碼:

/**
 * 代理工廠
 * 主要作用是生成代理對象
 */
public class ProxyFactory {
    //被代理對象
    private Object target;
    public ProxyFactory(Object target){
        this.target = target;
    }

    //為被代理對象生成代理對象
    public Object getProxyInstance(){
        return Proxy.newProxyInstance(
                //指定當前被代理對象使用的類加載器
                target.getClass().getClassLoader(),
                //指定被代理對象實現(xiàn)的接口類型,這里是一個數(shù)組,代理可能實現(xiàn)多個接口
                target.getClass().getInterfaces(),
                //事件處理,當我們在執(zhí)行被代理對象的方法的時候,會觸發(fā)這個處理器,會把當前執(zhí)行的被代理對象的方法作為參數(shù)傳入進去
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("執(zhí)行前置方法");
                        //執(zhí)行目標方法
                        Object returnValue = method.invoke(target, args);
                        System.out.println("執(zhí)行后置方法");
                        return returnValue;
                    }
                }
        );
    }
}
public class App {
    public static void main(String[] args) {
        //被代理對象
        Person target = new Man();
        System.out.println("被代理對象打印:"+target.getClass());
        //創(chuàng)建代理對象
        Person proxy = (Person) new ProxyFactory(target).getProxyInstance();

        System.out.println("代理對象打?。?+proxy.getClass());

        proxy.eat();

    }
}

結(jié)果:

被代理對象打?。篶lass com.luban.aop.proxy.statics.Man
代理對象打?。篶lass com.sun.proxy.$Proxy0
執(zhí)行前置方法
吃飯
執(zhí)行后置方法

缺點:在動態(tài)代理中,代理對象不需要再實現(xiàn)接口了,但是被代理對象還是需要實現(xiàn)接口,否則就無法使用動態(tài)代理

<a name="V4EnP"></a>

Cglib代理

什么是cglib代理,無論是動態(tài)代理還是靜態(tài)代理,都要求我們的被代理的對象必須要實現(xiàn)某一個接口,但是也可能存在這樣的情況,一個類沒有實現(xiàn)任何的接口,這個時候就可以使用cglib代理。

cglib代理是通過被代理對象的子類的形式來實現(xiàn)代理的,他會在內(nèi)存中構(gòu)建一個被代理對象的子類對象,來實現(xiàn)對被代理對象的功能的擴展。

在cglib的底層是通過一個字節(jié)碼處理框架ASM來轉(zhuǎn)換字節(jié)碼生成新的類

如果需要使用cglib的話,需要引入一個包 cglib

<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

上代碼

/**
 * 被代理類
 */
public class Woman {
    public void eat(){
        System.out.println("吃飯");
    }
}

/**
 * cglib 代理工廠類
 */
public class ProxyFactory implements MethodInterceptor {
    //被代理對象
    private Object target;

    public ProxyFactory(Object target){
        this.target = target;
    }
    //為被代理對象創(chuàng)建一個代理對象
    public Object getProxyInstance(){
        //這個是工具類
        Enhancer en = new Enhancer();
        //將被代理類設(shè)置為父類
        en.setSuperclass(target.getClass());
        //設(shè)置回調(diào)
        en.setCallback(this);
        //創(chuàng)建子類(代理對象)
        return en.create();
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("前置執(zhí)行....");
        //執(zhí)行被代理類的方法
        Object returnValue = method.invoke(target,objects);
        System.out.println("后置執(zhí)行....");
        return returnValue;
    }
}

public class App {
    public static void main(String[] args) {
        //被代理對象
        Woman target = new Woman();
        //代理對象
        Woman proxy = (Woman) new ProxyFactory(target).getProxyInstance();
        //執(zhí)行方法
        proxy.eat();
    }
}

執(zhí)行結(jié)果:

前置執(zhí)行....
吃飯
后置執(zhí)行....

注意:被代理對象的方法不能用final或者static

在springAOP中,如果被代理對象沒有實現(xiàn)接口則使用cglib,如果實現(xiàn)了接口則使用動態(tài)代理

免費在線視頻學(xué)習(xí),請訪問(持續(xù)更新中):java 教程 - 免費分享的視頻教程

更多的資訊請訪問QQ群:807167416

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

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

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