【设计模式】动态代理

本文介绍了Java动态代理的概念,对比了静态代理,强调了动态代理在运行时动态生成代理类的能力。通过一个UserManager的示例,展示了如何使用InvocationHandler的LogHandler类实现动态代理,实现方法调用前后的日志记录。动态代理的优势在于可以统一处理多个同一接口的实现类,使得代码更简洁,复用性更强。
摘要由CSDN通过智能技术生成

静态代理

想学,动态代理,须先知道什么是静态代理:【设计模式】静态代理

在编译时就已经将接口、被代理类、代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。最后带着这些确定的类运行程序。代理类在程序之前创建的代理方式被成为静态代理。

动态代理引出

而动态代理是指代理类在程序运行时创建的代理方式被成为动态代理。然而动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于,当我们存在多个代理类时,它可以很方便的对代理类进行统一的处理,而不用修改每个代理类中的方法。

我们直接上代码:仍然按照之前学静态代理举得的例子:
如下是UserManager和 UserManagerImpl的代码:UserManagerImpl实现了UserManager。
以下只是作为演示。

public interface UserManager {

    void addUser();

    void delUser();

    void findUser();

    void modifyUser();
}

public class UserManagerImpl implements UserManager {

    @Override
    public void addUser() {
        System.out.println("UserManagerImpl.addUser");
    }

    @Override
    public void delUser() {
        System.out.println("UserManagerImpl.delUser");
    }

    @Override
    public void findUser() {
        System.out.println("UserManagerImpl.findUser");
    }

    @Override
    public void modifyUser() {
        System.out.println("UserManagerImpl.modifyUser");

    }
}

=============================================================
1.定义一个LogHandler类(用来打印日志信息的Handler类)实现InvocationHandler类
2.在LogHandler类里重新包装Proxy.newProxyInstance(用来返回代理对象)
3.重写invoke方法,将核心业务(如打印日志)写进去。

public class LogHandler implements InvocationHandler {
    private Object target;//target千变万化,在这里其实就是实现类UserManagerImpl的对象(new UserManagerImpl)

    public Object newProxyInstance(Object target){
        this.target = target;//这个必须写,把方法作用域的target传给本类的target,否则invoke的target为null
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);//返回代理对象
    }
    @Override
    /*proxy表示代理,method表示原对象被调用的方法,args表示方法的参数*/
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result;
        try {
            System.out.println("start-->");
            result = method.invoke(target, args);//调用了target的具体方法
            System.out.println("success-->");
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("error-->>");
            throw e;
        }
        return result;
    }
}

对于LogHandler类:
newProxyInstance:返回代理的方法,这个过程为动态生成。没有一个具体的代理类能被看见。
invoke:调用实现类的对象的目标方法(替代目标方法)。

public class Client {
    public static void main(String[] args) {
        LogHandler logHandler = new LogHandler();
        UserManager proxyInstance = (UserManager) logHandler.newProxyInstance(new UserManagerImpl());//把实现类动态的托管给代理对象
        proxyInstance.addUser();//代理调用
        proxyInstance.delUser();
    }
}

通过debug发现,proxyInstance.addUser();这一行,实际上是调用LogHandler.invoke方法,method参数其实就是原来实现类对象中的addUser方法,method.invoke(target, args)才是调用了addUser方法,所以proxyInstance.addUser();走完是这样的:(proxyInstance.delUser();同理)
在这里插入图片描述
画个图总结一下吧:
在这里插入图片描述

代理对象proxy不能直观的显示出,由newProxyInstance创建,创建出来后,可以直观上调用目标实现类的方法,但其实质上是调用invoke方法,在invoke方法里才是调用目标实现类的方法,并且在此方法前后做业务拓展。
其次,动态代理模式下的代理对象proxy可以管理多个同一接口下的实现类。

动态代理优点:

  1. 一个代理类代理一个接口,一个接口对应的一类业务(例如本demo中的userManager用户管理)
  2. 一个代理类可以管理多个同一接口下的实现类。
  3. 接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。
  4. 动态代理的应用使我们的类职责更加单一,复用性更强。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

❀༊烟花易冷ღ

觉得博客写的不错就打赏一下吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值