Java动态代理——InvocationHandler和Proxy详解

Java 实现动态代理一共有两种方法,一种是JDK Proxy,另外一种是Cglib,下面就看看JDK动态代理的实现过程,和对实现JDK代理的一个接口InvocationHandler和一个类Proxy的详解。

首先我们说说静态代理跟动态代理的概念:

静态代理:就是由程序员自己创建或由特定工具自动生成源代码,在程序运行之前,代理类已经存在。(可参考设计模式中的代理模式)。

动态代理:在程序运行时,利用反射机制动态创建而成的。

JDK 代理

要代理的目标对象(委托类)必须实现接口,代理类只能对接口进行代理,要代理的目标对象(委托类)和代理列要实现相同的接口。

下面简单举个例子:


//接口
interfa  a {
 void sayHello();
}
//要代理的目标对象(委托类)
class  A implements a{

  public void sayHello(){
  System.out.println("hello,world");
  }
}

要对目标对象(委托类)进行代理 就必须也要实现 a这个接口,但是代理类不是通过直接 implements去实现的,下面会有实现接口a的方式。

在JDK 实现动态代理,我们得先了解一个重要的接口InvocationHandler(实现JDK代理必须实现这个类) 和一个重要的类Proxy

下面先说接口InvocationHandler的作用,看看官方文档对它的说明

InvocationHandler is the interface implemented by the invocation handler of a proxy instance.
Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

翻译成中文:

InvocationHandler是由代理实例的调用处理程序实现的接口 。

每个代理实例都有一个关联的调用处理程序。 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法。

也就是说我们代理类要调用目标对象(委托类)的方法都要经过InvocationHandler这个接口的invoke方法来调用。

看看InvocationHandler中唯一的一个方法invoke

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

三个参数的含义:

Object proxy:我们要代理的目标对象

Method method: 代理对象中实现了接口中方法的实例(这里有点抽象,其实就是代理对象实现了接口中的方法,这个方法也会调用目标对象(委托类)中的同一个方法)

Object [] args: 调用目标对象(委托类)中方法的参数

返回结果:目标对象类中的方法执行后返回的结果

这个方法看着是难以理解,但通过实际操作就比较容易了解这个方法的作用了,下面会有更详细的说明。

再看看Proxy类的官方文档对它描述

Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.

翻译成中文

Proxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。

说白了就是这个类提供了为我们创建代理类的方法,其中最常用的方法就是newProxyInstance()

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)throws IllegalArgumentException

三个参数的含义:

ClassLoader loader: 类加载器来定义代理类,用那个类加载器来加载代理对象

Class<?>[] interfaces: 代理类要实现的接口列表,就是代理类要实现哪些接口,这里是个数组,可以实现多个接口

InvocationHandler h:调度方法调用的调用处理函数(调用目标对象的handler)

返回结果:由指定的类加载器定义并实现指定接口的代理类的指定调用处理程序的代理实例

其实就返回我们的代理对象,下面有例子。

上面说了这么多,直接看个例子更容易理解吧。

接口

public interface A {

    void sayHello();


    int add(int a,int b);
}

目标对象(委托类)

public class AImpl implements A {

    @Override
    public void sayHello() {
        System.out.println("hello , world");
    }

    @Override
    public int add(int a, int b) {
        System.out.println("add()方法的执行结果:" + (a + b));
        return a + b;
    }
}

动态代理类

public class AProxy implements InvocationHandler {
    //我们要代理的目标对象(委托类)
    private AImpl A;

    //通过构造方法将我们的目标对象传进去
    public AProxy(AImpl a) {
        A = a;
    }
    //处理代理实例上的方法调用并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //在我们真正调用目标对象的方法之前和之后我们可以添加一些自己的操作,例如用户认证,日志记录等
        //例如在我们方法调用之前先进行用户验证,调用方法之后再用日志记录,下面用伪代码来说明
        System.out.println("对用户进行验证....验证通过,执行方法");
        //A是我们要进行代理的目标对象,args是执行目标对象中方法所需的参数
        Object invoke = method.invoke(A, args);
        System.out.println("目标对象方法执行后返回的结果:"+invoke);
        System.out.println("日志:记录用户的操作");
        System.out.println();
        //返回的是目标对象方法执行后的结果
        return invoke;
    }
}

客户类

newProxyInstance()方法返回的动态代理类是JVM运行时动态生成的

public class ProxyTestDemo {

    public static void main(String[] args) {
        //也可以用多态  A a = new AImpl()
        AImpl Aimpl = new AImpl();

        //将我们要代理的目标对象传进去
        AProxy aProxy = new AProxy(Aimpl);

        //创建目标对象的代理类

        A a = (A) Proxy.newProxyInstance(A.class.getClassLoader(), Aimpl.getClass().getInterfaces(), aProxy);
        
        a.sayHello();

        a.add(1, 2);


    }
}

运行结果

在这里插入图片描述

从运行结果可以看到我们在调用目标对象中的方法时,可以前后添加我们的一些操作,其实这跟Spring Aop中Adivce的差不多 ,上面添加的操作类似于前置通知,后置通知。

上面我们还说过InvacationHandler接口中invoke()方法的返回结果是我们目标对象方法执行后的结果,下面证明一下。

直接在动态代理类中添加下面的一句输出,看看在控制台中打印出看看是不是我们目标对象方法的运行结果。

在这里插入图片描述
控制台的输出结果

在这里插入图片描述

第一个方法没有返回值,所以返回null,第二个方法有返回值,所以直接返回目标对象方法的执行结果的返回值,通过上面的输出可以证明Method的invoke方法是返回目标对象方法的执行结果。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java动态代理是一种通过在运行时期间生成代理对象来实现对目标对象进行代理的技术。它可以在不修改目标对象的情况下,为目标对象提供额外的功能。 Java动态代理实现的核心是利用了Java的反射机制和动态生成类的技术。在动态代理中,我们需要定义一个代理类和一个实现了InvocationHandler接口的处理器类。 代理类是在运行时动态生成的类,它是目标对象的代理,它实现了与目标对象相同的接口,并且在方法调用时会通过InvocationHandler接口的实现类来处理方法的调用。InvocationHandler接口中只有一个方法invoke(Object proxy, Method method, Object[] args),这个方法就是用来处理方法调用的。 下面是一个简单的Java动态代理的示例代码: ``` import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynamicProxy implements InvocationHandler { private Object target; public DynamicProxy(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before method"); Object result = method.invoke(target, args); System.out.println("after method"); return result; } public static void main(String[] args) { RealObject realObject = new RealObject(); DynamicProxy dynamicProxy = new DynamicProxy(realObject); Interface proxyObject = (Interface) Proxy.newProxyInstance( Interface.class.getClassLoader(), new Class[] { Interface.class }, dynamicProxy); proxyObject.doSomething(); } } interface Interface { void doSomething(); } class RealObject implements Interface { public void doSomething() { System.out.println("RealObject doSomething"); } } ``` 在这个示例中,我们定义了一个DynamicProxy类作为代理处理器,它实现了InvocationHandler接口。在DynamicProxy类中,我们定义了一个Object类型的target属性,它表示目标对象。 在DynamicProxy类的invoke方法中,我们先输出了一句话“before method”,然后通过反射机制调用目标对象的方法,最后输出了一句话“after method”。 在DynamicProxy类的main方法中,我们首先创建了一个RealObject对象作为目标对象,然后创建了一个DynamicProxy对象,并将RealObject对象作为参数传递给DynamicProxy对象的构造方法。接着,我们通过Proxy.newProxyInstance方法动态生成了一个代理对象,并将DynamicProxy对象作为参数传递给它。最后,我们调用代理对象的doSomething方法。 当我们运行这个程序时,它会输出以下内容: ``` before method RealObject doSomething after method ``` 这表明,在代理对象调用doSomething方法时,它会先调用DynamicProxy类的invoke方法,在invoke方法中,我们将先输出一句话“before method”,然后调用目标对象的方法,最后输出一句话“after method”。 Java动态代理的优点是可以在运行时期间动态生成代理对象,不需要预先定义代理类,这样可以大大减少代码量。同时,Java动态代理也具有很好的灵活性,可以对不同的目标对象生成不同的代理对象,实现不同的处理逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值