【Java中级篇】动态代理机制

本文详细解释了代理模式的概念,对比了静态代理与动态代理的区别,通过实例展示了如何使用动态代理来增强方法调用,避免代码重复及提高维护性。

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

要想搞明白动态代理之前,我们先来了解一下代理是什么意思,先来谈谈设计模式中的代理模式。

什么是代理模式(Proxy)

定义:给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用。

在代理模式中,是需要代理对象和目标对象实现同一个接口(如果是不同的接口,那就是适配器模式了),看下面的UML图

                                            

为什么要用代理

最最最主要的原因就是,在不改变目标对象方法的情况下对方法进行增强,比如,我们希望对方法的调用增加日志记录,或者对方法的调用进行拦截,等等...

举一个例子

现有一个IPerson接口,只有一个方法say()

public interface IPerson {
    void say();
}

有一个Man类,实现了IPerson

public class Man implements IPerson{
    @Override
    public void say() {
        L.d("man say");
    }
}

现在需要在say方法被调用的时候,记录方法被调用的时间,最直接的就是修改Man的say方法,但是这样做的弊端就是如果有很多实现了IPerson接口的类,那就需要修改多处代码,而且这样的修改可能会导致其他的代码出问题(可能并不是所有的say都需要记录调用时间)。怎么办呢,这时候代理就要登场了!

静态代理

public class ManProxy implements IPerson{

    private IPerson target;

    public IPerson getTarget() {
        return target;
    }

    public ManProxy setTarget(IPerson target) {
        this.target = target;
        return this;
    }

    @Override
    public void say() {
        if (target != null) {
            L.d("man say invoked at : " + System.currentTimeMillis());
            target.say();
        }
    }
}

这样我们需要新建一个ManProxy类同样实现IPerson接口,将要代理的对象传递进来,这样就可以在不修改Man的say方法的情况下实现了我们的需求。这其实就是静态代理。那你可能要问,既然有了静态代理,为什么需要动态代理呢,因为静态代理有一个最大的缺陷:接口与代理类是1对1的,有多个接口需要代理,就需要新建多个代理类,繁琐,类爆炸

动态代理

我们先尝试用动态代理来解决上面的问题。先新建一个类实现InvocationHandler

public class NormalHandler implements InvocationHandler {

    private Object target;

    public NormalHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        L.d("man say invoked at : " + System.currentTimeMillis());
        method.invoke(target, args);
        return null;
    }
}

然后可以这样使用

		NormalHandler normalHandler = new NormalHandler(new Man());
		IPerson iPerson = (IPerson) Proxy.newProxyInstance(IPerson.class.getClassLoader(),
		                new Class[] {IPerson.class}, normalHandler);
		iPerson.say();

可以看到NormalHandler中代理的对象是Object类型,所以它是被多个接口代理复用的,这样就解决静态代理类爆炸,维护困难的问题。

接着我们发现执行iPerson.say()时,会被拦截从而执行NormalHandler中的invoke方法。

总结

1、代理模式的概念

2、静态代理和动态代理的区别

3、如何使用动态代理:

      3.1、创建被代理对象的接口IPerson 

      3.2、实现被代理的真实对象Man 

      3.3、创建调用处理器NormalHandler 

      3.4、生成代理对象

 

 

本文参考:https://blog.youkuaiyun.com/u011552404/article/details/79954199https://www.jianshu.com/p/6e962d1e7ddd

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值