彻底搞懂java动态代理

代理的目的是什么?

不修改函数代码同时扩展函数的功能

代理实现有几种?

静态代理和动态代理

静态代理是啥?
比如有个A类,里面有个b函数,处理事情c,返回结果d

class A{
    public String b() {
        System.out.println("c...");
        return "d";
    }
}
//怎么调用?
A a=new A();
a.b();

如果现在有一个需求:不改变A类的b方法里面的代码,但是又要扩展b函数的功能,要有一些新功能,你咋整?可能的思路有这么几个1、写一个E类继承A然后重写b方法 2、写一个F类,F持有A的实例,F也有一个b方法,F的b方法里面会调用A的b方法,同时F的b方法还有一些新功能代码。其实思路1就是继承出现的原因,思路2就是代理出现的原因,我们写出思路2的代码

class E{
	class A a;
	E (A az){
		a=az;
	}    
    public String b() {
    	insertNew();//这里插入新功能代码
        String z=a.b();//我们调用了A类的b函数
        return z;
    }
}
//怎么调用?
A a=new A();
E e=new E(a);
e.b();
//很明显,我们调用E的b函数的时候,除了会完成A的b函数方法之外,还会完成新功能代码

那以前调用是A.b,现在调用是E.b这样子就需要修改调用方法的地方,那怎么做到不需要修改调用者呢?接口就出现了。

public interface G{
    public String b();
}

我们将有b函数的类抽象成为一个接口,所有实现了b函数的类,都可以用接口来调用,当然我们看下修改后的代码

class A implements G{
    public String b() {
        System.out.println("c...");
        return "d";
    }
}
//怎么调用?
G g=new A();
g.b();

class E implements G{
	class A a;
	E (G az){
		a=az;
	}    
    public String b() {
    	insertNew();//这里插入新功能代码
        String z=a.b();//我们调用了A类的b函数
        return z;
    }
}
//怎么调用?
G a=new A();
G g=new E(a);
g.b();//这就是接口调用

动态代理是啥
回顾下静态代理,总结就是:代理类和原始类实现同一个接口、在代理类中持有原始类、代理类的方法中调用原始类的函数(同时可以写新功能代码扩充功能)。静态代理就一个个这样子实现,动态代理就是任意给一个类自动实现这种代理模式。动态到底啥意思?就是动态创建对象,动态调用函数。
怎么动态创建类?

Proxy类newProxyInstance的就可以动态创建类的对象。

怎么动态调用函数?

InvocationHandler接口的invoke就可以动态调用函数
public class Proxy implements java.io.Serializable {
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

我们跟踪Proxy 和InvocationHandler 源码发现,Proxy可以帮助我们动态创建类,代理类和原始类都实现了InvocationHandler接口的invoke方法,这样子就实现了动态代理。我们看个具体的例子

public class E implements InvocationHandler{

    //代理类中的真实对象  
    private Object obj;

    public E() {
    }
    //构造函数,给我们的真实对象赋值
    public E(Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //在真实的对象执行之前我们可以添加自己的操作
        System.out.println("before invoke。。。");
        Object invoke = method.invoke(obj, args);
        //在真实的对象执行之后我们可以添加自己的操作
        System.out.println("after invoke。。。");
        return invoke;
    }
}
	//怎么调用
	//新建原始类的对象
	Object target =new A();
	//指明动态调用的函数
	TransactionHandler handler =new InvocationHandler(a);
	//动态生成代理类
	G g= (G)Proxy.newProxyInstance(target.getClass().getClassLoader(),
	target.getClass().getInterfaces(),handler);
	//接口进行方法调用
	g.b();

动态代理的本质
其实动态代理的本质,就是将写静态代理的代码的过程的交给编译器帮我们去实现了。我们编译程序之后找到E.class字节码,然后用JD打开就可以看到java代码,其实里面的和我们手动写的静态代理代码差不多。
参考资料
Java动态代理详解 https://v.ixigua.com/ecVBtkS/
JDK动态代理的底层实现之Proxy源码分析 https://www.cnblogs.com/liuyun1995/p/8157098.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值