亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Java三種代理模式:靜態(tài)代理、動(dòng)態(tài)代理和cglib代理

Kaede / 1801人閱讀

摘要:動(dòng)態(tài)代理又被稱為代理或接口代理。靜態(tài)代理在編譯時(shí)產(chǎn)生字節(jié)碼文件,可以直接使用,效率高。代理無(wú)需實(shí)現(xiàn)接口,通過(guò)生成類字節(jié)碼實(shí)現(xiàn)代理,比反射稍快,不存在性能問(wèn)題,但會(huì)繼承目標(biāo)對(duì)象,需要重寫方法,所以目標(biāo)對(duì)象不能為類。

一、代理模式介紹

代理模式是一種設(shè)計(jì)模式,提供了對(duì)目標(biāo)對(duì)象額外的訪問(wèn)方式,即通過(guò)代理對(duì)象訪問(wèn)目標(biāo)對(duì)象,這樣可以在不修改原目標(biāo)對(duì)象的前提下,提供額外的功能操作,擴(kuò)展目標(biāo)對(duì)象的功能。

簡(jiǎn)言之,代理模式就是設(shè)置一個(gè)中間代理來(lái)控制訪問(wèn)原目標(biāo)對(duì)象,以達(dá)到增強(qiáng)原對(duì)象的功能和簡(jiǎn)化訪問(wèn)方式。

代理模式UML類圖

舉個(gè)例子,我們生活中經(jīng)常到火車站去買車票,但是人一多的話,就會(huì)非常擁擠,于是就有了代售點(diǎn),我們能從代售點(diǎn)買車票了。這其中就是代理模式的體現(xiàn),代售點(diǎn)代理了火車站對(duì)象,提供購(gòu)買車票的方法。

二、靜態(tài)代理

這種代理方式需要代理對(duì)象和目標(biāo)對(duì)象實(shí)現(xiàn)一樣的接口。

優(yōu)點(diǎn):可以在不修改目標(biāo)對(duì)象的前提下擴(kuò)展目標(biāo)對(duì)象的功能。

缺點(diǎn):

冗余。由于代理對(duì)象要實(shí)現(xiàn)與目標(biāo)對(duì)象一致的接口,會(huì)產(chǎn)生過(guò)多的代理類。

不易維護(hù)。一旦接口增加方法,目標(biāo)對(duì)象與代理對(duì)象都要進(jìn)行修改。

舉例:保存用戶功能的靜態(tài)代理實(shí)現(xiàn)

接口類: IUserDao

package com.proxy;

public interface IUserDao {
    public void save();
}

目標(biāo)對(duì)象:UserDao

package com.proxy;

public class UserDao implements IUserDao{

    @Override
    public void save() {
        System.out.println("保存數(shù)據(jù)");
    }
}

靜態(tài)代理對(duì)象:UserDapProxy 需要實(shí)現(xiàn)IUserDao接口!

package com.proxy;

public class UserDaoProxy implements IUserDao{

    private IUserDao target;
    public UserDaoProxy(IUserDao target) {
        this.target = target;
    }
    
    @Override
    public void save() {
        System.out.println("開(kāi)啟事務(wù)");//擴(kuò)展了額外功能
        target.save();
        System.out.println("提交事務(wù)");
    }
}

測(cè)試類:TestProxy

package com.proxy;

import org.junit.Test;

public class StaticUserProxy {
    @Test
    public void testStaticProxy(){
        //目標(biāo)對(duì)象
        IUserDao target = new UserDao();
        //代理對(duì)象
        UserDaoProxy proxy = new UserDaoProxy(target);
        proxy.save();
    }
}

輸出結(jié)果

開(kāi)啟事務(wù)
保存數(shù)據(jù)
提交事務(wù)
三、動(dòng)態(tài)代理

動(dòng)態(tài)代理利用了JDK API,動(dòng)態(tài)地在內(nèi)存中構(gòu)建代理對(duì)象,從而實(shí)現(xiàn)對(duì)目標(biāo)對(duì)象的代理功能。動(dòng)態(tài)代理又被稱為JDK代理或接口代理。

靜態(tài)代理與動(dòng)態(tài)代理的區(qū)別主要在:

靜態(tài)代理在編譯時(shí)就已經(jīng)實(shí)現(xiàn),編譯完成后代理類是一個(gè)實(shí)際的class文件

動(dòng)態(tài)代理是在運(yùn)行時(shí)動(dòng)態(tài)生成的,即編譯完成后沒(méi)有實(shí)際的class文件,而是在運(yùn)行時(shí)動(dòng)態(tài)生成類字節(jié)碼,并加載到JVM中

特點(diǎn):
動(dòng)態(tài)代理對(duì)象不需要實(shí)現(xiàn)接口,但是要求目標(biāo)對(duì)象必須實(shí)現(xiàn)接口,否則不能使用動(dòng)態(tài)代理。

JDK中生成代理對(duì)象主要涉及的類有

java.lang.reflect Proxy,主要方法為

static Object    newProxyInstance(ClassLoader loader,  //指定當(dāng)前目標(biāo)對(duì)象使用類加載器

 Class[] interfaces,    //目標(biāo)對(duì)象實(shí)現(xiàn)的接口的類型
 InvocationHandler h      //事件處理器
) 
//返回一個(gè)指定接口的代理類實(shí)例,該接口可以將方法調(diào)用指派到指定的調(diào)用處理程序。

java.lang.reflect InvocationHandler,主要方法為

 Object    invoke(Object proxy, Method method, Object[] args) 
// 在代理實(shí)例上處理方法調(diào)用并返回結(jié)果。

舉例:保存用戶功能的動(dòng)態(tài)代理實(shí)現(xiàn)

接口類: IUserDao

package com.proxy;

public interface IUserDao {
    public void save();
}

目標(biāo)對(duì)象:UserDao

package com.proxy;

public class UserDao implements IUserDao{

    @Override
    public void save() {
        System.out.println("保存數(shù)據(jù)");
    }
}

動(dòng)態(tài)代理對(duì)象:UserProxyFactory

package com.proxy;

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

public class ProxyFactory {

    private Object target;// 維護(hù)一個(gè)目標(biāo)對(duì)象

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

    // 為目標(biāo)對(duì)象生成代理對(duì)象
    public Object getProxyInstance() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new InvocationHandler() {

                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("開(kāi)啟事務(wù)");

                        // 執(zhí)行目標(biāo)對(duì)象方法
                        Object returnValue = method.invoke(target, args);

                        System.out.println("提交事務(wù)");
                        return null;
                    }
                });
    }
}

測(cè)試類:TestProxy

package com.proxy;

import org.junit.Test;

public class TestProxy {

    @Test
    public void testDynamicProxy (){
        IUserDao target = new UserDao();
        System.out.println(target.getClass());  //輸出目標(biāo)對(duì)象信息
        IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
        System.out.println(proxy.getClass());  //輸出代理對(duì)象信息
        proxy.save();  //執(zhí)行代理方法
    }
}

輸出結(jié)果

class com.proxy.UserDao
class com.sun.proxy.$Proxy4
開(kāi)啟事務(wù)
保存數(shù)據(jù)
提交事務(wù)
四、cglib代理

cglib is a powerful, high performance and quality Code Generation Library. It can extend JAVA classes and implement interfaces at runtime.

cglib (Code Generation Library )是一個(gè)第三方代碼生成類庫(kù),運(yùn)行時(shí)在內(nèi)存中動(dòng)態(tài)生成一個(gè)子類對(duì)象從而實(shí)現(xiàn)對(duì)目標(biāo)對(duì)象功能的擴(kuò)展。

cglib特點(diǎn)

JDK的動(dòng)態(tài)代理有一個(gè)限制,就是使用動(dòng)態(tài)代理的對(duì)象必須實(shí)現(xiàn)一個(gè)或多個(gè)接口。
如果想代理沒(méi)有實(shí)現(xiàn)接口的類,就可以使用CGLIB實(shí)現(xiàn)。

CGLIB是一個(gè)強(qiáng)大的高性能的代碼生成包,它可以在運(yùn)行期擴(kuò)展Java類與實(shí)現(xiàn)Java接口。
它廣泛的被許多AOP的框架使用,例如Spring AOP和dynaop,為他們提供方法的interception(攔截)。

CGLIB包的底層是通過(guò)使用一個(gè)小而快的字節(jié)碼處理框架ASM,來(lái)轉(zhuǎn)換字節(jié)碼并生成新的類。
不鼓勵(lì)直接使用ASM,因?yàn)樗枰銓?duì)JVM內(nèi)部結(jié)構(gòu)包括class文件的格式和指令集都很熟悉。

cglib與動(dòng)態(tài)代理最大的區(qū)別就是

使用動(dòng)態(tài)代理的對(duì)象必須實(shí)現(xiàn)一個(gè)或多個(gè)接口

使用cglib代理的對(duì)象則無(wú)需實(shí)現(xiàn)接口,達(dá)到代理類無(wú)侵入。

使用cglib需要引入cglib的jar包,如果你已經(jīng)有spring-core的jar包,則無(wú)需引入,因?yàn)閟pring中包含了cglib。

cglib的Maven坐標(biāo)


    cglib
    cglib
    3.2.5

舉例:保存用戶功能的動(dòng)態(tài)代理實(shí)現(xiàn)

目標(biāo)對(duì)象:UserDao

package com.cglib;

public class UserDao{

    public void save() {
        System.out.println("保存數(shù)據(jù)");
    }
}

代理對(duì)象:ProxyFactory

package com.cglib;

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 ProxyFactory implements MethodInterceptor{

    private Object target;//維護(hù)一個(gè)目標(biāo)對(duì)象
    public ProxyFactory(Object target) {
        this.target = target;
    }
    
    //為目標(biāo)對(duì)象生成代理對(duì)象
    public Object getProxyInstance() {
        //工具類
        Enhancer en = new Enhancer();
        //設(shè)置父類
        en.setSuperclass(target.getClass());
        //設(shè)置回調(diào)函數(shù)
        en.setCallback(this);
        //創(chuàng)建子類對(duì)象代理
        return en.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("開(kāi)啟事務(wù)");
        // 執(zhí)行目標(biāo)對(duì)象的方法
        Object returnValue = method.invoke(target, args);
        System.out.println("關(guān)閉事務(wù)");
        return null;
    }
}

測(cè)試類:TestProxy

package com.cglib;

import org.junit.Test;

public class TestProxy {

    @Test
    public void testCglibProxy(){
        //目標(biāo)對(duì)象
        UserDao target = new UserDao();
        System.out.println(target.getClass());
        //代理對(duì)象
        UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance();
        System.out.println(proxy.getClass());
        //執(zhí)行代理對(duì)象方法
        proxy.save();
    }
}

輸出結(jié)果

class com.cglib.UserDao
class com.cglib.UserDao$$EnhancerByCGLIB$$552188b6
開(kāi)啟事務(wù)
保存數(shù)據(jù)
關(guān)閉事務(wù)
五、總結(jié)

靜態(tài)代理實(shí)現(xiàn)較簡(jiǎn)單,只要代理對(duì)象對(duì)目標(biāo)對(duì)象進(jìn)行包裝,即可實(shí)現(xiàn)增強(qiáng)功能,但靜態(tài)代理只能為一個(gè)目標(biāo)對(duì)象服務(wù),如果目標(biāo)對(duì)象過(guò)多,則會(huì)產(chǎn)生很多代理類。

JDK動(dòng)態(tài)代理需要目標(biāo)對(duì)象實(shí)現(xiàn)業(yè)務(wù)接口,代理類只需實(shí)現(xiàn)InvocationHandler接口。

動(dòng)態(tài)代理生成的類為 lass com.sun.proxy.$Proxy4,cglib代理生成的類為class com.cglib.UserDao$$EnhancerByCGLIB$$552188b6。

靜態(tài)代理在編譯時(shí)產(chǎn)生class字節(jié)碼文件,可以直接使用,效率高。

動(dòng)態(tài)代理必須實(shí)現(xiàn)InvocationHandler接口,通過(guò)反射代理方法,比較消耗系統(tǒng)性能,但可以減少代理類的數(shù)量,使用更靈活。

cglib代理無(wú)需實(shí)現(xiàn)接口,通過(guò)生成類字節(jié)碼實(shí)現(xiàn)代理,比反射稍快,不存在性能問(wèn)題,但cglib會(huì)繼承目標(biāo)對(duì)象,需要重寫方法,所以目標(biāo)對(duì)象不能為final類。

六、相關(guān)資料

代理模式相關(guān)知識(shí)

代理模式及Java實(shí)現(xiàn)動(dòng)態(tài)代理

設(shè)計(jì)模式讀書筆記 - 代理模式

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

Java 動(dòng)態(tài)代理機(jī)制分析及擴(kuò)展

Java代理(jdk靜態(tài)代理、動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理)

AOP的底層實(shí)現(xiàn)-CGLIB動(dòng)態(tài)代理和JDK動(dòng)態(tài)代理

深入淺出CGlib-打造無(wú)入侵的類代理

Spring AOP 實(shí)現(xiàn)原理與 CGLIB 應(yīng)用

UML相關(guān)知識(shí)

博客 - UML類圖與類的關(guān)系詳解

goole圖書 -《UML建模實(shí)例詳解》

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/70513.html

相關(guān)文章

  • Java三種代理模式

    Java的三種代理模式 參考:http://www.cnblogs.com/cenyu/...Java核心技術(shù)原書第九版6.5節(jié) 為什么使用代理   我們?cè)趯懸粋€(gè)功能函數(shù)時(shí),經(jīng)常需要在其中寫入與功能不是直接相關(guān)但很有必要的代 碼,如日志記錄,信息發(fā)送,安全和事務(wù)支持等,這些枝節(jié)性代碼雖然是必要的,但它會(huì)帶來(lái)以下麻煩: 枝節(jié)性代碼游離在功能性代碼之外,它不是函數(shù)的目的,這是對(duì)OO是一種破壞 枝節(jié)性...

    Rango 評(píng)論0 收藏0
  • Java設(shè)計(jì)模式代理模式

    摘要:設(shè)計(jì)模式之代理模式今天學(xué)到的動(dòng)態(tài)代理實(shí)現(xiàn),對(duì)代理這個(gè)概念很模糊,看了一篇文章發(fā)現(xiàn)這是一種設(shè)計(jì)模式,于是學(xué)習(xí)記錄一下。簡(jiǎn)介代理模式是一種對(duì)象結(jié)構(gòu)型的模式,主要為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問(wèn)。下面依次講解著三種代理。 設(shè)計(jì)模式之代理模式 今天學(xué)到Spring的動(dòng)態(tài)代理實(shí)現(xiàn)AOP,對(duì)代理這個(gè)概念很模糊,看了一篇文章發(fā)現(xiàn)這是一種設(shè)計(jì)模式,于是學(xué)習(xí)記錄一下。 簡(jiǎn)介 代理模式是一種對(duì)...

    ZHAO_ 評(píng)論0 收藏0
  • JAVA代理模式的理解應(yīng)用

    摘要:代理模式代理模式通俗一點(diǎn)的解釋就是在操作一個(gè)對(duì)象和對(duì)象中的方法時(shí),不是直接操作這個(gè)對(duì)象,還是通過(guò)一個(gè)代理對(duì)象來(lái)操作這個(gè)實(shí)際的目標(biāo)對(duì)象。 代理模式: 代理模式通俗一點(diǎn)的解釋就是在操作一個(gè)對(duì)象和對(duì)象中的方法時(shí),不是直接操作這個(gè)對(duì)象,還是通過(guò)一個(gè)代理對(duì)象來(lái)操作這個(gè)實(shí)際的目標(biāo)對(duì)象。應(yīng)用場(chǎng)景一般是需要在執(zhí)行某個(gè)已經(jīng)寫好的方法前后再添加一段邏輯,比如執(zhí)行方法前打印日志,或者在執(zhí)行方法之前和之后打時(shí)...

    CatalpaFlat 評(píng)論0 收藏0
  • 淺入淺出Java代理三種實(shí)現(xiàn)

    摘要:代理模式的實(shí)現(xiàn)靜態(tài)代理優(yōu)缺點(diǎn)優(yōu)點(diǎn)只對(duì)對(duì)需要的方法加代理邏輯。通過(guò)繼承的方式進(jìn)行代理,無(wú)論目標(biāo)對(duì)象有沒(méi)有實(shí)現(xiàn)接口都可以代理,但是無(wú)法處理的情況。 注意:本文所有的class使用的static修飾主要是為了能在一個(gè)類里面測(cè)試。實(shí)際項(xiàng)目中不應(yīng)該這樣做的,應(yīng)該分包分class。文字描述不是很多,還是看代碼比較好理解吧... 1. Java代理的理解 代理模式是一種設(shè)計(jì)模式,簡(jiǎn)單說(shuō)即是在不改變?cè)?..

    lewif 評(píng)論0 收藏0
  • 設(shè)計(jì)模式代理模式

    摘要:下面我們通過(guò)玩英雄聯(lián)盟代練的例子來(lái)說(shuō)明下登錄游戲贏下了一局英雄聯(lián)盟,獲得了金幣測(cè)試結(jié)果登錄游戲贏下了一局英雄聯(lián)盟,獲得了金幣可以這樣理解,自己寫代理類的方式就是靜態(tài)代理。 前言 剛上大學(xué)那會(huì),英雄聯(lián)盟火的一塌糊涂,當(dāng)時(shí)每天都想著升到30級(jí)開(kāi)啟排位之旅。可是升到30級(jí)需要大把的時(shí)間不說(shuō),這時(shí)候匹配到的人,水平過(guò)于參差不齊,問(wèn)候你全家的事經(jīng)常發(fā)生,那個(gè)時(shí)候就想要是能有個(gè)代練幫我升到30級(jí)該...

    xuweijian 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<