關於Java動態代理的一點想法

來源:互聯網
上載者:User

標籤:動態代理


如有錯誤請指正

1.    動態代理的作用

 1. 虛擬機器產生的動態代理對象可以輕鬆地對原有方法進行各種重寫

 2. 若沒有動態代理,想實現重寫,必須做一個繼承基類的子類



2.  執行個體示範:

package com.didi.test;


public interface Person {


    String skill();


    String play();

}



    package com.didi.test;


public class Programmer implements  Person{



    @Override

    public String skill() {

        System.out.println("coding-------------------------");

        return "調用skill方法";

    }


    @Override

    public String play() {

        return null;

    }

}

   

       package com.didi.test;


import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;


public class MyInvocationHandler implements InvocationHandler {


    Programmer programmer;


    public MyInvocationHandler(Programmer programmer) {

        this.programmer = programmer;

    }


    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("before------------");

        System.out.println(proxy.getClass().getName());

        Object obj =  method.invoke(programmer);

        System.out.println("after----------------------");

        if(!method.getName().equals("skill")){

            return "調用娛樂方法";

        }

        return obj;

    }

}

package com.didi.test;


import java.lang.reflect.Proxy;


public class ProxTest {


    public static void main(String[] args) {

        Programmer p = new Programmer();

        Person programmerProxy = (Person)Proxy.newProxyInstance(

                ProxTest.class.getClassLoader(),

               p.getClass().getInterfaces(),

                new MyInvocationHandler(p));

        System.out.println("動態代理類的父類:" + programmerProxy.getClass().getSuperclass().getName());

        String mes = programmerProxy.play();

        System.out.println(mes);

    }

}

控制台列印:

動態代理類的父類:java.lang.reflect.Proxy

before------------

com.sun.proxy.$Proxy0

after----------------------

調用娛樂方法


3. 底層實現原理


 1. 如下源碼:

     public static Object newProxyInstance(ClassLoader loader,

                                          Class<?>[] interfaces,

                                          InvocationHandler h)

        throws IllegalArgumentException

    {

        Objects.requireNonNull(h);


        final Class<?>[] intfs = interfaces.clone();

        final SecurityManager sm = System.getSecurityManager();

        if (sm != null) {

            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);

        }


        /*

         * Look up or generate the designated proxy class.

         */

        Class<?> cl = getProxyClass0(loader, intfs);


        /*

         * Invoke its constructor with the designated invocation handler.

         */

        try {

            if (sm != null) {

                checkNewProxyPermission(Reflection.getCallerClass(), cl);

            }


            final Constructor<?> cons = cl.getConstructor(constructorParams);

            final InvocationHandler ih = h;

            if (!Modifier.isPublic(cl.getModifiers())) {

                AccessController.doPrivileged(new PrivilegedAction<Void>() {

                    public Void run() {

                        cons.setAccessible(true);

                        return null;

                    }

                });

            }

            return cons.newInstance(new Object[]{h});

        } catch (IllegalAccessException|InstantiationException e) {

            throw new InternalError(e.toString(), e);

        } catch (InvocationTargetException e) {

            Throwable t = e.getCause();

            if (t instanceof RuntimeException) {

                throw (RuntimeException) t;

            } else {

                throw new InternalError(t.toString(), t);

            }

        } catch (NoSuchMethodException e) {

            throw new InternalError(e.toString(), e);

        }

    }


 2. 源碼解析

 Proxy.newProxyInstance產生代理類對象,這個方法做了兩件重要的事情,首先產生實現傳入介面的實作類別,然後通過反射建立對象,建立對象時傳入一個參數,即我們自己實現的MyInvocationHandler


3. 具體運行情況

當運行代理對象的方法時,虛擬機器做如下處理:

1.收集三個參數:代理對象的引用,當前調用方法的方法名,方法的參數

2.調用MyInvocationHandler的invoke方法,參數為上一步收集的參數


4. 實際應用

    1. 日誌,交易管理

    2. 遠端程序呼叫RPC,遠程調用時,具體實現在服務端,這時我們在invoke中實現通訊即可(調用方法時,讓遠端的方法被調用,將結果發揮即可),這一切都是通過invoke中的socket通訊實現的

 

 囉嗦一下:

 通過動態代理可以輕鬆地對一個類進行方法增強,改造,自訂

 

      


關於Java動態代理的一點想法

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.