Java 动态代理类

一、什么是代理?

代理是一种常用的设计模式,其目的就是为真实对象提供一个代理对象以控制对真实对象的访问。代理类负责为委托类(被代理类、真实类)预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
这里写图片描述

为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。

二、Java 动态代理类

Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:

(1)Interface InvocationHandler:该接口中仅定义了一个方法

public Object invoke(Object obj,Method method, Object[] args)

public object invoke(Object obj,Method method, Object[] args)
在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。

(2)Proxy:该类即为动态代理类,其中主要包含以下内容:

protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。

static Class getProxyClass (ClassLoaderloader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)

所谓DynamicProxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个DynamicProxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

在使用动态代理类时,我们必须实现InvocationHandler接口

通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。

动态代理步骤:

  1. 创建被代理的类(委托类、真实类)(RealSubject)及其接口(RealSubjectInterface)
  2. 创建一个实现接口InvocationHandler的类(InvocationHandlerImpl),它必须实现接口的invoke方法
  3. 通过Proxy的静态方法newProxyInstance(), 创建一个代理对象(realSubjectProxy),
    RealSubjectInterface realSubjectProxy= (RealSubjectInterface) Proxy.newProxyInstance(loader,interfaces,handler);
  4. 通过代理对象(realSubjectProxy)调用 委托类对象( realSubject)的方法

三、JDK的动态代理 实现步骤?

1.创建被代理的类的接口RealSubjectInterface

package cn.alibaba.dynamic_proxy;

/**
 * 真实对象的实现接口:需要动态代理的接口
 */
public interface RealSubjectInterface {
    /**
     *定义方法
     */
    public String SayHello(String name);

    public String SayGoodBye();

}

2、创建被代理的类(委托类、真实类)RealSubject

package cn.alibaba.dynamic_proxy;

public class RealSubject implements RealSubjectInterface{
    @Override
    public String SayHello(String name) {

        return "hello, " + name;
    }

    @Override
    public String SayGoodBye() {

        return " good bye ";
    }
}

3、创建一个实现接口InvocationHandler的类InvocationHandlerImpl
即调用处理器实现类(传说中的AOP?)

package cn.alibaba.dynamic_proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 *调用处理器实现类(有木有感觉这里就是传说中的AOP啊)
 * 每次生成动态代理类对象的时候都需要指定一个实现了该接口的调用处理器类
 *  */

public class InvocationHandlerImpl implements InvocationHandler{
    /**
     * 我们要代理的真实对象
     */
    private Object realSubject;//为了new InvocationHandlerImpl(realSubject);传参名一致

    /**
     * 构造函数,为真实对象赋初值
     */
    public InvocationHandlerImpl(Object realSubject){
        this.realSubject =realSubject;
    }
    /**
     * invoke方法负责处理动态代理类中所有方法调用
     * 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //在代理真实对象前可以添加额外操作
        System.out.println("在用代理对象调用真实对象的方法之前,类似AOP的Before(),自己的操作:");
        System.out.println("其调用的方法Method:"+method);

        //当代理对象调用真实对象的方法时,其会自动跳转到代理对象关联的handler对象的invoke方法来进行调用
        Object returnValue=method.invoke(realSubject,args);

        //在代理真实对象之后可以添加额外操作
        System.out.println("在用代理对象调用真实对象的方法之后,但是返回值returnValue之前,自己的操作?");

        return returnValue;
        }
}

4、动态代理测试

package cn.alibaba.dynamic_proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * 动态代理测试
 */
public class DynamicProxyDemonstration {
    public static void main(String[] args) {
        //创建要被代理的真实对象
        RealSubjectInterface realSubject=new RealSubject();

        /**
         * InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
         * 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用.
         * 即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法
         */
        InvocationHandler handler =new InvocationHandlerImpl(realSubject);

        ClassLoader loader=realSubject.getClass().getClassLoader();
        Class []interfaces=realSubject.getClass().getInterfaces();

        /**
         * Proxy.newProxyInstance该方法用于为指定类加载器,一组接口,调用处理器生成动态代理类对象
         */
        RealSubjectInterface realSubjectProxy= (RealSubjectInterface) Proxy.newProxyInstance(loader,interfaces,handler);

        System.out.println("动态代理对象的类型:"+realSubjectProxy.getClass().getName());

        //用动态代理类对象 调用 真实对象的方法
        System.out.println(realSubjectProxy.SayHello("Jason zhang"));

        //System.out.println("/*************************************/");

       // System.out.println(realSubjectProxy.SayGoodBye());

    }

}

5、测试结果
这里写图片描述

四、源码分析过程

参考:https://blog.csdn.net/jiankunking/article/details/52143504

分析newProxyInstance()源码发现:最终真正的代理类,它继承自Proxy并实现了我们定义的RealSubjectInterface 接口

RealSubjectInterface realSubjectProxy= (RealSubjectInterface) Proxy.newProxyInstance(loader,interfaces,handler);

这里的realSubjectProxy实际是这个类的一个实例,那么我们调用它的:

public String SayHello(String name);

就是调用我们定义的InvocationHandlerImpl的 invoke方法:
这里写图片描述

五、结论

realSubjectProxy.SayHello(“Jason zhang”)这句话时,为什么会自动调用InvocationHandlerImpl的invoke方法?

因为JDK生成的最终真正的代理类,它继承自Proxy并实现了我们定义的RealSubjectInterface 接口,在实现RealSubjectInterface 接口方法的内部,通过反射调用了InvocationHandlerImpl 的invoke方法

代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。

通过分析代码可以看出Java 动态代理,具体有如下四步骤:

  1. 通过实现 InvocationHandler 接口创建自己的调用处理器类;
  2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
  3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
  4. 通过构造函数创建动态代理类实例,构造时调用处理器对象(handler)作为参数被传入。

猜你喜欢

转载自blog.csdn.net/hefenglian/article/details/81194569