java反射之动态代理学习笔记

本文详细介绍了如何使用Java动态代理创建代理对象的过程。通过一个具体的示例,解释了代理类的生成原理,包括如何利用Proxy类的newProxyInstance方法生成代理类,以及调用处理器(InvocationHandler)的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面是我写的一个小demo,先来看代码

package com.csdn.demo;

import com.zhang.jian.zhang;

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

/**
 * Created by zhang on 2016/12/16.
 * 定义Person接口
 */
interface Person {
    String say(String name);
}
/**
*定义Student接口
*/
interface Student{
    String study(String name);
}
/**
 * Created by zhang on 2016/12/16.
 * 定义User类实现Person 和 Student 接口,重写接口方法
 */
class User implements Person,Student {
    public String study(String name) {
        System.out.println("User正在学习:"+name);
        return name;
    }

    public String say(String name) {
        System.out.println("Person的say方法:" + name);
        return name;
    }
}
/**
 * Created by zhang on 2016/12/16.
 * 定义 嗯... 我管它叫调用处理器
 * 这个主要是用到invoke()方法,作用后面详细介绍
 */
class MyInvocationHandler implements InvocationHandler {
    Object obj = null;
/**
 * Created by zhang on 2016/12/16.
 * 这个方法起到了两个作用 
 * 1、给obj赋值,将被代理类赋值给obj
 * 2、该方法返回一个 实现了被代理类实现的所有接口 的代理类,或者说它返回一个代理类-->被代理类实现的那些
 * 接口-->生成的代理类也都实现了(具体后面介绍)
 */
    public Object blind(Object obj) {
        this.obj = obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }
/**
 * Created by zhang on 2016/12/16.
 * invoke方法的作用:生成的代理类要重写实现的接口的方法,重写的方法就是来调用这个invoke()方法
 */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("进入了invoke方法了!");
        Object returnValue = method.invoke(obj, args);
        return returnValue;
    }
}

public class TestProxy {
    public static void main(String[] args) {
        User user=new User();
        MyInvocationHandler handler = new MyInvocationHandler();
        Student personProxy = (Student) handler.blind(user);
        personProxy.study("Tom");
    }

}

运行结果:

进入了invoke方法了!
User正在学习:Tom

Process finished with exit code 0
下面我们来好好分析一下代理类的生成过程

a)调用Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);这条语句生成代理类。
第一个参数:传入被代理类的类类加载器
第二个参数:传入被代理类实现的所有接口
第三个参数:this也就是我们写的那个调用处理器
(如果你对这里有疑虑的话,建议先去看看Class的相关内容:只简单说一下通过Class可以在运行时得到一个类的完整结构)
然后我们点开Proxy的源码文件,发现newProxyInstance方法有如下一条语句
Class<?> cl = getProxyClass(loader, interfaces);
紧接着

 Constructor cons = cl.getConstructor(constructorParams);
            return cons.newInstance(new Object[] { h });

不难看出它是通过getProxyClass(loader,interfaces)//loader是传入的类加载器,interfaces是传入的所有接口---
方法返回了一个实现了所有接口的代理类的Class,即这么个东西Class<T>,其中T就是代理类。

b)我们继续去看getProxyClass(loader,interfaces),发现它用到了一个这样的数据类型
static Map<ClassLodar,Map<List<String>,Object>>,通过读代码我们发现这是Proxy用来缓存代理类的,ClassLoader不用说了就是类加载器,List<String>保存的是传入的所有接口的名字,而对应的代理类就保存在Object中。
根据你的传入参数,来判断如果之前已经生成了相应的代理类就直接拿出来返回。
如果没有生成过这样的代理类就调用如下一条语句来生成,并把它缓存起来

//proxyClass就是返回结果,所以Class<T>是通过这个方法生成的
 proxyClass = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
 //好吧,这个方法是这样定义的,是的我们看到了native关键字,说明这个方法的实现并不是用java写的
 //~那么进行到这里就先结束了(已经懒得再去找了)因为我们已经完全可以进行一下合理的推断了~
  private static native Class defineClass0(ClassLoader loader, String name,
                                             byte[] b, int off, int len);

c)到这里我们已经大体知道代理类是如何生成的了,只是一些细节还不清楚,但是通过程序的运行结果我们可以来合理的推断。
- 当我们运行上面程序中的代理类personProxy.study("Tom")时,执行的是调用处理器的invoke方法
- 在创建代理类的时候我们传入了一个参数this,也就是调用处理器。生成代理类是这样一条语句return cons.newInstance(new Object[] { h });
- 以上两点,说明生成的代理类有一个构造方法,参数就是一个调用处理器的列表,因此我们也可以推断,代理类的方法的实现就是调用了调用处理器的invoke方法,因此我们只要重写invoke方法就是间接实现了代理类的方法。这就是JDK暴露给我们的一个接口。

到了这里我们是不是对AOP面向切面编程有了初步的认识呢?在调用处理器的invoke方法中如果我们在Object returnValue = method.invoke(obj, args);的上面和下面写点什么东西,是不是就等于在上下两个代码段之间可以动态插入代码了呢?

待更新…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值