欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入解析java中的靜態(tài)代理與動態(tài)代理

 更新時間:2013年10月12日 09:46:48   作者:  
本篇文章是對java中的靜態(tài)代理與動態(tài)代理進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下,希望對大家有所幫助

java編碼中經(jīng)常用到代理,代理分為靜態(tài)代理和動態(tài)代理。其中動態(tài)代理可以實(shí)現(xiàn)spring中的aop。

一、靜態(tài)代理:程序運(yùn)行之前,程序員就要編寫proxy,然后進(jìn)行編譯,即在程序運(yùn)行之前,代理類的字節(jié)碼文件就已經(jīng)生成了

被代理類的公共父類

復(fù)制代碼 代碼如下:

package staticproxy;
public abstract class BaseClass {
    public abstract void add();
}

被代理類
復(fù)制代碼 代碼如下:

package staticproxy;
public class A extends BaseClass {
    public void add() {
        System.out.println("A add !");
    }
}

代理類
復(fù)制代碼 代碼如下:

package staticproxy;
public class Proxy {
    BaseClass baseClass;
    public void add() {
        baseClass.add();
    }
    public void setBaseClass(BaseClass baseClass) {
        this.baseClass = baseClass;
    }
    public static void main(String[] args) {
        BaseClass baseClass = new A();
        Proxy proxy = new Proxy();
        proxy.setBaseClass(baseClass);
        proxy.add();
    }
}

二、動態(tài)代理:實(shí)際的代碼在編譯期間并沒有生成,而是在運(yùn)行期間運(yùn)用反射機(jī)制動態(tài)的生成

被代理類接口

復(fù)制代碼 代碼如下:

package jdkproxy;
public interface Service {
    public void add();
    public void update();
}

被代理類A
復(fù)制代碼 代碼如下:

package jdkproxy;
public class AService implements Service {
    public void add() {
        System.out.println("AService add>>>>>>>>>>>>>>>>>>");
    }
    public void update() {
        System.out.println("AService update>>>>>>>>>>>>>>>");
    }
}

被代理類B
復(fù)制代碼 代碼如下:

package jdkproxy;
public class BService implements Service {
    public void add() {
        System.out.println("BService add---------------");
    }
    public void update() {
        System.out.println("BService update---------------");
    }
}

代理類
復(fù)制代碼 代碼如下:

package jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
    private Object target;
    MyInvocationHandler() {
        super();
    }
    MyInvocationHandler(Object target) {
        super();
        this.target = target;
    }
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        // 程序執(zhí)行前加入邏輯
        System.out.println("before-----------------------------");
        // 程序執(zhí)行
        Object result = method.invoke(target, args);
        //程序執(zhí)行后加入邏輯
        System.out.println("after------------------------------");
        return result;
    }
    public Object getTarget() {
        return target;
    }
    public void setTarget(Object target) {
        this.target = target;
    }
}

測試類
復(fù)制代碼 代碼如下:

package jdkproxy;
import java.lang.reflect.Proxy;
public class Test {
    public static void main(String[] args) {
        Service aService = new AService();
        MyInvocationHandler handler = new MyInvocationHandler(aService);
        // Proxy為InvocationHandler實(shí)現(xiàn)類動態(tài)創(chuàng)建一個符合某一接口的代理實(shí)例
        Service aServiceProxy = (Service) Proxy.newProxyInstance(aService
                .getClass().getClassLoader(), aService.getClass()
                .getInterfaces(), handler);
        //由動態(tài)生成的代理對象來aServiceProxy 代理執(zhí)行程序,其中aServiceProxy 符合Service接口
        aServiceProxy.add();
        System.out.println();
        aServiceProxy.update();
        // 以下是對B的代理
        // Service bService = new BService();
        // MyInvocationHandler handler = new MyInvocationHandler(bService);
        // Service bServiceProxy = (Service) Proxy.newProxyInstance(bService
        // .getClass().getClassLoader(), bService.getClass()
        // .getInterfaces(), handler);
        // bServiceProxy.add();
        // System.out.println();
        // bServiceProxy.update();
    }
}

輸出結(jié)果:
before-----------------------------
AService add>>>>>>>>>>>>>>>>>>
after------------------------------
before-----------------------------
AService update>>>>>>>>>>>>>>>
after------------------------------

其中上述標(biāo)紅的語句是產(chǎn)生代理類的關(guān)鍵代碼,可以產(chǎn)生一個符合Service接口的代理對象,newProxyInstance這個方法會做這樣一件事情,他將把你要代理的全部接口,用一個由代碼動態(tài)生成的類來實(shí)現(xiàn),該類中所有的接口中的方法都重寫為調(diào)用InvocationHandler.invoke()方法。

下面詳細(xì)介紹是如何實(shí)現(xiàn)代理對象的生成的

Proxy的newProxyInstance方法,其中,為了看起來方便,已經(jīng)將該方法中的異常處理語句刪減

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

復(fù)制代碼 代碼如下:

    public static Object newProxyInstance(ClassLoader loader,  Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException 
    { 
        if (h == null) { 
            throw new NullPointerException(); 
        } 
        //生成指定的代理類
        Class cl = getProxyClass(loader, interfaces); 
        Constructor cons = cl.getConstructor(constructorParams); 
        // 生成代理類的實(shí)例,并把MyInvocationHandler的實(shí)例傳給它的構(gòu)造方法,代理類對象實(shí)際執(zhí)行都會調(diào)用MyInvocationHandler的invoke方法,所以代理類對象中維持一個MyInvocationHandler引用 
        return (Object) cons.newInstance(new Object[] { h }); 
    }  其中g(shù)etProxyClass方法返回代理類的實(shí)例

Proxy的getProxyClass方法
復(fù)制代碼 代碼如下:

public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException
{
    //前面省略很多緩存、異常處理、判斷邏輯代碼,為了使程序更加突出
    byte[] proxyClassFile =    ProxyGenerator.generateProxyClass(proxyName, interfaces);
    proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
    proxyClasses.put(proxyClass, null);
    return proxyClass;
}

下面看ProxyGenerator的generateProxyClass方法,該方法最終產(chǎn)生代理類的字節(jié)碼文件:
復(fù)制代碼 代碼如下:

public static byte[] generateProxyClass(final String name, Class[] interfaces) 
   { 
       ProxyGenerator gen = new ProxyGenerator(name, interfaces); 
    // 這里動態(tài)生成代理類的字節(jié)碼
       final byte[] classFile = gen.generateClassFile(); 
    // 如果saveGeneratedFiles的值為true,則會把所生成的代理類的字節(jié)碼保存到硬盤上 
       if (saveGeneratedFiles) { 
           java.security.AccessController.doPrivileged( 
           new java.security.PrivilegedAction<Void>() { 
               public Void run() { 
                   try { 
                       FileOutputStream file = 
                           new FileOutputStream(dotToSlash(name) + ".class"); 
                       file.write(classFile); 
                       file.close(); 
                       return null; 
                   } catch (IOException e) { 
                       throw new InternalError( 
                           "I/O exception saving generated file: " + e); 
                   } 
               } 
           }); 
       } 
    // 返回代理類的字節(jié)碼 
       return classFile; 
   }

那么最終生成的代理類到底是什么樣子呢,如下(省略了一下equals,hashcode,toString等方法,只展示構(gòu)造函數(shù)和add方法):
復(fù)制代碼 代碼如下:

public final class $Proxy11 extends Proxy implements Service 
{      // 構(gòu)造方法,參數(shù)就是剛才傳過來的MyInvocationHandler類的實(shí)例 
    public $Proxy11(InvocationHandler invocationhandler) 
    { 
        super(invocationhandler); 
    } 

    /**
     * 繼承的add方法,重寫,調(diào)用MyInvocationHandler中的invoke方法
     */ 
    public final void add() 
    { 
        try 
        { 
            // 實(shí)際上就是調(diào)用MyInvocationHandler中的invoke方法 
            super.h.invoke(this, m3, null); 
            return; 
        } 
        catch(Error _ex) { } 
       catch(Throwable throwable) 
        { 
            throw new UndeclaredThrowableException(throwable); 
        } 
   } 

相關(guān)文章

  • spring整合redis消息監(jiān)聽通知使用的實(shí)現(xiàn)示例

    spring整合redis消息監(jiān)聽通知使用的實(shí)現(xiàn)示例

    在電商系統(tǒng)中,秒殺,搶購,紅包優(yōu)惠卷等操作,一般都會設(shè)置時間限制,本文主要介紹了spring整合redis消息監(jiān)聽通知使用,具有一定的參考價值,感興趣的可以了解一下
    2021-12-12
  • Java使用Condition實(shí)現(xiàn)精準(zhǔn)喚醒線程詳解

    Java使用Condition實(shí)現(xiàn)精準(zhǔn)喚醒線程詳解

    這篇文章主要為大家詳細(xì)介紹了Java如何使用Condition實(shí)現(xiàn)精準(zhǔn)喚醒線程效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下
    2023-02-02
  • SpringBoot整合微信小程序支付V3(支付退款)

    SpringBoot整合微信小程序支付V3(支付退款)

    小程序支付在很多項(xiàng)目都會使用,本文主要介紹了SpringBoot整合微信小程序支付V3,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09
  • Mybatis中關(guān)于自定義mapper.xml時,參數(shù)傳遞的方式及寫法

    Mybatis中關(guān)于自定義mapper.xml時,參數(shù)傳遞的方式及寫法

    這篇文章主要介紹了Mybatis中關(guān)于自定義mapper.xml時,參數(shù)傳遞的方式及寫法,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • 解決mac最新版intellij idea崩潰閃退crash的問題

    解決mac最新版intellij idea崩潰閃退crash的問題

    這篇文章主要介紹了解決mac最新版intellij idea崩潰閃退crash的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • springboot3整合遠(yuǎn)程調(diào)用的過程解析

    springboot3整合遠(yuǎn)程調(diào)用的過程解析

    遠(yuǎn)程過程調(diào)用主要分為:服務(wù)提供者,服務(wù)消費(fèi)者,通過連接對方服務(wù)器進(jìn)行請求交互,來實(shí)現(xiàn)調(diào)用效果,這篇文章主要介紹了springboot3整合遠(yuǎn)程調(diào)用,需要的朋友可以參考下
    2023-06-06
  • 解決Springboot項(xiàng)目bootstrap.yml不生效問題

    解決Springboot項(xiàng)目bootstrap.yml不生效問題

    Spring Boot 2.4版本開始,配置文件加載方式進(jìn)行了重構(gòu),只會識別application.* 配置文件,并不會自動識別bootstrap.yml,所以本文給大家介紹Springboot項(xiàng)目bootstrap.yml不生效問題的解決方案,需要的朋友可以參考下
    2023-09-09
  • springboot中spring.profiles.include的妙用分享

    springboot中spring.profiles.include的妙用分享

    這篇文章主要介紹了springboot中spring.profiles.include的妙用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Java?DelayQueue實(shí)現(xiàn)延時任務(wù)的示例詳解

    Java?DelayQueue實(shí)現(xiàn)延時任務(wù)的示例詳解

    DelayQueue是一個無界的BlockingQueue的實(shí)現(xiàn)類,用于放置實(shí)現(xiàn)了Delayed接口的對象,其中的對象只能在其到期時才能從隊列中取走。本文就來利用DelayQueue實(shí)現(xiàn)延時任務(wù),感興趣的可以了解一下
    2022-08-08
  • RocketMQ源碼解析broker?啟動流程

    RocketMQ源碼解析broker?啟動流程

    這篇文章主要為大家介紹了RocketMQ源碼解析broker啟動流程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03

最新評論