如有错误请指正

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通信实现的

 

 啰嗦一下:

 通过动态代理可以轻松地对一个类进行方法增强,改造,自定义