Java动态代理

一、Java动态代理简介

Java动态代理机制中有两个重要的类和接口:InvocationHandler(接口)Proxy(类)是实现动态代理的核心。

        InvocationHandler接口:是  proxy代理类实例的调用处理程序  所实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序。在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法。每一个  动态代理类的调用处理程序  都必须实现InvocationHandler接口,并重写InvocationHandler接口的invoke()方法,并且每个代理类的实例都关联到了实现该接口的动态代理类调用处理程序中,当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转到实现InvocationHandler接口类的invoke方法来调用,invoke方法参数说明如下:

//重写InvocationHandler接口的invoke()方法
/*
* Object proxy:代理类代理的真实代理对象
* Method method:我们所要调用的某个真实对象要执行的方法的Method对象
* Object[] args:代理对象方法需要传进来的所有参数
* */
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {}

        Proxy类:用来创建一个代理对象,其最常用的方法是newProxyInstance()方法。

//通过Proxy类的newProxyInstance()方法创建代理对象
//要代理哪个真实对象,就将该真实对象传进去,最后通过该真实对象来调用其方法
/*
* ClassLoader loader:要创建哪个真实对象的代理对象
*       使用真实代理对象的类加载器来告诉 代理对象的调用程序 要创建 哪个真实对象的代理对象
* Class[] interfaces:为代理类提供的接口
*       使用真实代理对象的类加载器来告诉 代理对象的调用程序 要代理的真实对象实现的所有接口
* InvocationHandler h:将代理对象关联到InvocationHandler对象上
*       告诉 代理对象 去找哪个 代理对象的调用程序
* */
//通过Proxy类的newProxyInstance()方法创建代理对象
//要代理哪个真实对象,就将该真实对象传进去,最后通过该真实对象来调用其方法
/*
* ClassLoader loader:要创建哪个真实对象的代理对象
*       使用真实代理对象的类加载器来告诉 代理对象的调用程序 要创建 哪个真实对象的代理对象
* Class[] interfaces:为代理类提供的接口
*       使用真实代理对象的类加载器来告诉 代理对象的调用程序 要代理的真实对象实现的所有接口
* InvocationHandler h:将代理对象关联到InvocationHandler对象上
*       告诉 代理对象 去找哪个 代理对象的调用程序
* */
public static Object newProxyInstance(ClassLoader loader, 
                                      Class[] interfaces, 
                                      InvocationHandler h) {}

二、具体举例

动态代理步骤:

1、创建需要代理的接口

2、创建需要代理的真实对象(类)

3、创建一个实现接口InvocationHandler的类(动态代理类(对象)的调用处理程序),它必须重写invoke方法

4、通过Proxy的静态方法newProxyInstance()创建一个代理类对象,通过代理调用方法

1、需要动态代理的接口:

//需要动态代理的接口
public interface People {
    //打招呼
    public String sayHello(String name);
    //说再见
    public String sayGoodBye();
}

2、需要代理的实际对象

定义一个Teacher类,实现People接口,这个类是需要代理的真实对象

//需要被代理的真实对象
public class Teacher implements People{

    @Override
    public String sayHello(String name) {
        System.out.println("你好!");
        return "Hello" + name;
    }

    @Override
    public String sayGoodBye() {
        System.out.println("再见!");
        return "GoodBye";
    }
}

3、动态代理类(对象)的调用处理程序

定义一个代理类的调用处理程序,每个 动态代理类的调用处理程序 都必须实现InvocationHandler接口,重写其中的invoke()方法;我们将要代理的真实对象传入代理对象的调用处理程序的构造函数中,最终代理对象的调用处理程序会调用真实对象的方法;当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用

//动态代理类(对象)的调用处理程序
/*每个 动态代理类的调用处理程序 都必须实现InvocationHandler接口,重写其中的invoke()方法
我们将要代理的真实对象传入代理对象的调用处理程序的构造函数中,最终代理对象的调用处理程序会调用真实对象的方法
当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用
*/
public class InvocationHandlerImpl implements InvocationHandler {

    //声明代理类中要代理的真实对象(为了普用性,声明为Object类型,可以传进来多种类型的要代理的真实对象)
    private Object realObject;

    //提供构造函数,给要代理的真实对象赋值(动态的把要代理的真实对象传进来)
    public InvocationHandlerImpl() {
    }
    public InvocationHandlerImpl(Object realObject) {
        this.realObject = realObject;
    }

    //重写InvocationHandler接口的invoke()方法
    /*
    * Object proxy:代理类代理的真实代理对象
    * Method method:我们所要调用的某个真实对象要执行的方法的Method对象
    * Object[] args:代理对象方法需要传进来的所有参数
    * */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //在真实对象执行之前,我们可以添加自己的操作
        System.out.println("真实代理对象执行前,我先干点啥!");

        Object invoke = method.invoke(realObject, args);

        //在真实对象执行之后,我们可以添加自己的操作
        System.out.println("真实代理对象执行后,我再干点啥!");

        return invoke;
    }
}

4、创建代理对象测试

通过Proxy的静态方法newProxyInstance()创建一个代理类对象,通过代理调用方法

public class dynamicProxyTest {

    public static void main(String[] args) {

        //创建我们需要代理的真实对象
        People realTeacher = new Teacher();

        //创建 代理对象的调用程序 的对象
        //将要代理的真实对象传入代理对象的调用处理的构造函数中,最终代理对象的调用处理程序会调用真实对象的方法
        InvocationHandler handler = new InvocationHandlerImpl(realTeacher);

        //通过Proxy类的newProxyInstance()方法创建代理对象
        //要代理哪个真实对象,就将该真实对象传进去,最后通过该真实对象来调用其方法
        /*
        * realTeacher.getClass().getClassLoader():要创建哪个真实对象的代理对象
        *       使用真实代理对象的类加载器来告诉 代理对象的调用程序 要创建 哪个真实对象的代理对象
        * realTeacher.getClass().getInterfaces():为代理类提供的接口
        *       使用真实代理对象的类加载器来告诉 代理对象的调用程序 要代理的真实对象实现的所有接口
        * handler:将代理对象关联到InvocationHandler对象上
        *       告诉 代理对象 去找哪个 代理对象的调用程序
        * */
        People proxyInstance = (People) Proxy.newProxyInstance(realTeacher.getClass().getClassLoader(),
                                                                realTeacher.getClass().getInterfaces(),
                                                                handler);

//        System.out.println("动态代理生成的类:" + proxyInstance.getClass().getName());
//        System.out.println(proxyInstance.toString());

        String hello = proxyInstance.sayHello("爱神!");
        System.out.println("返回值:" + hello);

        System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@");

        String goodBye = proxyInstance.sayGoodBye();
        System.out.println("返回值:" + goodBye);

    }

}

执行结果如下图:

Java动态代理_第1张图片

在Spring中的两大核心IOC和AOP中的AOP(面向切面编程)的思想就是动态代理,在代理类的前面和后面加上不同的切面组成面向切面编程。上面只使用了Proxy类中的newProxyInstance()静态方法(生成代理类的方法),但是它还有其它的几个方法:

getInvocationHandler:返回指定代理实例的调用处理程序
getProxyClass:给定类加载器和接口数组的代理类的java.lang.Class对象。
isProxyClass:当且仅当使用getProxyClass方法或newProxyInstance方法将指定的类动态生成为代理类时,才返回true。
newProxyInstance:返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。

Java 动态代理具体有如下四步骤:

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

参考文章:

原文链接:https://blog.csdn.net/jiankunking/article/details/52143504
原文链接:https://blog.csdn.net/yaomingyang/article/details/80981004

你可能感兴趣的:(java,代理模式,spring)