深入解析java中的靜態代理與動態代理_java

來源:互聯網
上載者:User

java編碼中經常用到代理,代理分為靜態代理和動態代理。其中動態代理可以實現spring中的aop。

一、靜態代理:程式運行之前,程式員就要編寫proxy,然後進行編譯,即在程式運行之前,代理類的位元組碼檔案就已經產生了

被代理類的公用父類

複製代碼 代碼如下:

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

被代理類
複製代碼 代碼如下:

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

代理類
複製代碼 代碼如下:

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

二、動態代理:實際的代碼在編譯期間並沒有產生,而是在運行期間運用反射機制動態產生

被代理類介面

複製代碼 代碼如下:

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

被代理類A
複製代碼 代碼如下:

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

被代理類B
複製代碼 代碼如下:

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

代理類
複製代碼 代碼如下:

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 {
        // 程式執行前加入邏輯
        System.out.println("before-----------------------------");
        // 程式執行
        Object result = method.invoke(target, args);
        //程式執行後加入邏輯
        System.out.println("after------------------------------");
        return result;
    }
    public Object getTarget() {
        return target;
    }
    public void setTarget(Object target) {
        this.target = target;
    }
}

測試類別
複製代碼 代碼如下:

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實作類別動態建立一個符合某一介面的代理執行個體
        Service aServiceProxy = (Service) Proxy.newProxyInstance(aService
                .getClass().getClassLoader(), aService.getClass()
                .getInterfaces(), handler);
        //由動態產生的代理對象來aServiceProxy 代理執行程式,其中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();
    }
}

輸出結果:
before-----------------------------
AService add>>>>>>>>>>>>>>>>>>
after------------------------------
before-----------------------------
AService update>>>>>>>>>>>>>>>
after------------------------------

其中上述標紅的語句是產生代理類的關鍵代碼,可以產生一個符合Service介面的代理對象,newProxyInstance這個方法會做這樣一件事情,他將把你要代理的全部介面,用一個由代碼動態產生的類來實現,該類中所有的介面中的方法都重寫為調用InvocationHandler.invoke()方法。

下面詳細介紹是如何?代理對象的產生的

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

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

複製代碼 代碼如下:

    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); 
        // 組建代理程式類的執行個體,並把MyInvocationHandler的執行個體傳給它的構造方法,代理類對象實際執行都會調用MyInvocationHandler的invoke方法,所以代理類對象中維持一個MyInvocationHandler引用 
        return (Object) cons.newInstance(new Object[] { h }); 
    }  其中getProxyClass方法返回代理類的執行個體

Proxy的getProxyClass方法
複製代碼 代碼如下:

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方法,該方法最終產生代理類的位元組碼檔案:
複製代碼 代碼如下:

public static byte[] generateProxyClass(final String name, Class[] interfaces) 
   { 
       ProxyGenerator gen = new ProxyGenerator(name, interfaces); 
    // 這裡動態組建代理程式類的位元組碼
       final byte[] classFile = gen.generateClassFile(); 
    // 如果saveGeneratedFiles的值為true,則會把所產生的代理類的位元組碼儲存到硬碟上 
       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); 
                   } 
               } 
           }); 
       } 
    // 返回代理類的位元組碼 
       return classFile; 
   }

那麼最終產生的代理類到底是什麼樣子呢,如下(省略了一下equals,hashcode,toString等方法,只展示建構函式和add方法):
複製代碼 代碼如下:

public final class $Proxy11 extends Proxy implements Service 
{      // 構造方法,參數就是剛才傳過來的MyInvocationHandler類的執行個體 
    public $Proxy11(InvocationHandler invocationhandler) 
    { 
        super(invocationhandler); 
    } 

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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.