什么是动态代理
1.动态代理是java中一个非常重要的技术,很多javaWeb框架都用到了这个技术,就比如spring中的事务管理。
2.动态代理技术就是用来产生一个对象的代理对象的
我们查看javaAPI,发现proxy主要有四个方法,最常用的就是最下面一个
原对象和代理对象之间的关系
代理对象应该具有和原对象相同的方法,就比如一个明星和它的经纪人的关系,明星一般不会自己过去谈生意,而是经纪人去,就好比一个公司找这个明星唱歌,那他应该先去找明星的经纪人,但是经纪人实际上是不会唱歌的,所以经纪人最后才会去找这个明星
如何生成代理对象
下面我们通过这个方法来产生指定对象的代理对象
观察这个方法发现里面有三个参数,他们的作用如下
ClassLoader loader:指明生成代理对象使用哪个类装载器,白话的意思就是生成之后的代理对象你要用哪个类来装它(代理对象)
Class<?>[] interfaces:指明生成哪个对象的代理对象,看到interface可以知道能知道为什么java中规定,要想产生一个对象的代理对象,那么这个对象必须要有一个接口这句话是为什么了
InvocationHandler h:这个代理对象要做什么事情
下面我们就写具体例子来实现
首先肯定要有个接口
然后是它的实现类
然后写个代理类
**
* 明星的代理类
* ClassName:StartProxy
* Author:LFM
* Date:2019/7/25 11:24
**/
public class StartProxy {
//先把明星传进来,这样代理类才能知道要代理谁啊
//因为要提供一个接口,所以用接口声明这个明星对象的引用
private Person start = new Start();
//写一个方法返回明星的代理对象了
public Person getProxy(){
//调用方法
return (Person)Proxy.newProxyInstance(Start.class.getClassLoader(),
start.getClass().getInterfaces(),
new InvocationHandler() {
//可以看出,这里我们使用了内部类
//因为这个InvocationHandler接口只有一个方法
//我们称这个样的接口叫做函数式接口,官方建议使用内部类或者lambda表达式
//这个方法有三个参数
//Object proxy:传入代理对象
//Method method:传入代理对象的当前方法
//Object[] args:把方法的参数也传进来
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//这里可以让代理对象做一些操作(例如经纪人在这里谈生意)
//所以这里调用的就是代理对象的方法
//这个getName()是用来得到方法名的
if (method.getName().equals("song")){
System.out.println("我是该明星的经纪人,钱给到位马上安排!!");
}
//公司给够钱了,但是经纪人不会唱歌,所以现在就去找明星来唱
//所以这里调用的就是原对象的方法
return method.invoke(start,args);
}
});
}
然后写个测试类
结果
最后说一点儿小问题,就是JDK1.8之后内部类调用外部类的成员变量的时候,成员变量不用手动加final关键字了,底层Java帮我们实现了,所以可以看到我这边那个传入进来的成员变量没有加final关键字
我们可以看出,在动态代理技术里,由于不管用户调用代理对象的什么方法,最后都是调用处理器的invoke方法。所以利用这个invoke()方法的参数(代理对象的方法名和参数),就可以知道用户调用的是什么方法,利用这个特性,就可以实现一些特殊需求,例如动态为某个对象添加额外的功能,就可以进行AOP操作,就像是spring中事务的管理。