Java动态代理

芙蓉生在秋江上,不向东风怨未开

上一篇写了Java的静态代理的使用方法,动态代理要比静态代理稍微复杂一点。

动态代理

首先定义一个接口:

/**
 * @author aRunner
 * @date 2020/5/11
 */
public interface Person {
    /**
     *@author aRunner
     *@date 2020/5/11
     *@description 睡觉方法
     */
    public void sleep(String time) ;
    /**
     *@author aRunner
     *@date 2020/5/11
     *@description 吃饭方法
     */
    public void eat(String something) ;
}

定义被代理的类:

/**
 * @author aRunner
 * @date 2020/5/11
 */
public class Student implements Person {


    @Override
    public void sleep(String time) {
        System.out.println("Student 正在睡" + time);
    }

    @Override
    public void eat(String something) {
        System.out.println("Student 正在吃" + something);
    }
}

现在编写动态代理的类:

import java.lang.reflect.Proxy;

/**
 * 动态代理,动态代理类不要显示的实现被代理类所实现的接口
 * @author aRunner
 *
 */
public class MyInvocationHandler  {
    public static void main(String [] args){
        //创建需要被代理的类
        Student s = new Student();
        Person person = (Person) Proxy.newProxyInstance(s.getClass().getClassLoader(), s.getClass().getInterfaces(), (proxy, method, params) -> {
            if (method.getName().equals("sleep")) {
                System.out.println("Student 准备睡觉");
                return method.invoke(s, params);
            } else if (method.getName().equals("eat")) {
                System.out.println("Student 准备吃饭");
                return method.invoke(s, params);
            }
            return null;
        });
        person.sleep("午觉");
        person.eat("午饭");
    }
}

打印结果:
Java动态代理_第1张图片

动态代理详解

newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler h)方法
该方法的参数解释:
Java动态代理_第2张图片

  • loder,选用的类加载器。
  • interfaces,被代理的类所实现的接口,这个接口可以是多个。
  • h,绑定代理类的一个方法。

loder和interfaces基本就是决定了这个类到底是个怎么样的类。而h是InvocationHandler,决定了这个代理类到底是多了什么功能。所以动态代理的内容重点就是这个InvocationHandler。

InvocationHandler
先来看看该接口的注释:

 	 * Processes a method invocation on a proxy instance and returns
     * the result.  This method will be invoked on an invocation handler
     * when a method is invoked on a proxy instance that it is
     * associated with.
     *
     * @param   proxy the proxy instance that the method was invoked on
     *
     * @param   method the {@code Method} instance corresponding to
     * the interface method invoked on the proxy instance.  The declaring
     * class of the {@code Method} object will be the interface that
     * the method was declared in, which may be a superinterface of the
     * proxy interface that the proxy class inherits the method through.
     *
     * @param   args an array of objects containing the values of the
     * arguments passed in the method invocation on the proxy instance,
     * or {@code null} if interface method takes no arguments.
     * Arguments of primitive types are wrapped in instances of the
     * appropriate primitive wrapper class, such as
     * {@code java.lang.Integer} or {@code java.lang.Boolean}.
     *
     * @return  the value to return from the method invocation on the
     * proxy instance.  If the declared return type of the interface
     * method is a primitive type, then the value returned by
     * this method must be an instance of the corresponding primitive
     * wrapper class; otherwise, it must be a type assignable to the
     * declared return type.  If the value returned by this method is
     * {@code null} and the interface method's return type is
     * primitive, then a {@code NullPointerException} will be
     * thrown by the method invocation on the proxy instance.  If the
     * value returned by this method is otherwise not compatible with
     * the interface method's declared return type as described above,
     * a {@code ClassCastException} will be thrown by the method
     * invocation on the proxy instance.

根据注解描述可知,InvocationHandler作用就是,当代理对象的原本方法被调用的时候,会绑定执行一个方法,这个方法就是InvocationHandler里面定义的内容,同时会替代原本方法的结果返回。

动态代理实现原理

来看看newProxyInstance()方法的源码:

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

首先是克隆一个接口:final Class[] intfs = interfaces.clone();,然后通过参数中的类加载器和克隆出来的接口,拿到代理类:Class cl = getProxyClass0(loader, intfs);,再通过反射技术,利用代理类获取代理类的构造函数:final Constructor cons = cl.getConstructor(constructorParams);,最后通过构造函数new一个对象出来:return cons.newInstance(new Object[]{h});,同时用InvocationHandler绑定这个对象。

本文参考至:你真的完全了解Java动态代理吗?看这篇就够了

你可能感兴趣的:(java)