动态代理在 Java 中有着广泛的应用,比如 AOP 的实现原理、RPC远程调用、Java 注解对象获取、日志框架、全局性异常处理、事务处理等。
在了解动态代理前,我们需要先了解一下什么是代理模式。
代理模式代理模式(Proxy Pattern)是 23 种设计模式的一种,属于结构型模式。他指的是一个对象本身不做实际的操作,而是通过其他对象来得到自己想要的结果。这样做的好处是可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
这里能体现出一个非常重要的编程思想:不要随意去改源码,如果需要修改,可以通过代理的方式来扩展该方法。
如上图所示,用户不能直接使用目标对象,而是构造出一个代理对象,由代理对象作为中转,代理对象负责调用目标对象真正的行为,从而把结果返回给用户。
也就是说,代理的关键点就是代理对象和目标对象的关系。
代理其实就和经纪人一样,比如你是一个明星,有很多粉丝。你的流量很多,经常会有很多金主来找你洽谈合作等,你自己肯定忙不过来,因为你要处理的不只是谈合作这件事情,你还要懂才艺、拍戏、维护和粉丝的关系、营销等。为此,你找了一个经纪人,你让他负责和金主谈合作这件事,经纪人做事很认真负责,它圆满的完成了任务,于是,金主找你谈合作就变成了金主和你的经纪人谈合作,你就有更多的时间来忙其他事情了。如下图所示
这是一种静态代理,因为这个代理(经纪人)是你自己亲自挑选的。
但是后来随着你的业务逐渐拓展,你无法选择每个经纪人,所以你索性交给了代理公司来帮你做。如果你想在 B 站火一把,那就直接让代理公司帮你找到负责营销方面的代理人,如果你想维护和粉丝的关系,那你直接让代理公司给你找一些托儿就可以了,那么此时的关系图会变为如下
此时你几乎所有的工作都是由代理公司来进行打理,而他们派出谁来帮你做这些事情你就不得而知了,这得根据实际情况来定,因为代理公司也不只是负责你一个明星,而且每个人所擅长的领域也不同,所以你只有等到有实际需求后,才会给你指定对应的代理人,这种情况就叫做动态代理。
静态代理从编译期是否能确定最终的执行方法可以把代理模式分为静态代理和动态代理,我们先演示一下动态代理,这里有一个需求,领导想在系统中添加一个用户,但是他不自己添加,他让下面的程序员来添加,我们看一下这个过程。
首先构建一个用户接口,定义一个保存用户的模版方法。
public interface UserDao { void saveUser(); }构建一个用户实现类,这个用户实现类是真正进行用户操作的方法
public class UserDaoImpl implements UserDao{ @Override public void saveUser() { System.out.println(" ---- 保存用户 ---- "); } }构建一个用户代理类,用户代理类也有一个保存用户的方法,不过这个方法属于代理方法,它不会执行真正的保存用户,而是内部持有一个真正的用户对象,进行用户保存。
public class UserProxy { private UserDao userDao; public UserProxy(UserDao userDao){ this.userDao = userDao; } public void saveUser() { System.out.println(" ---- 代理开始 ---- "); userDao.saveUser(); System.out.println(" ---- 代理结束 ----"); } }下面是测试方法。
public class UserTest { public static void main(String[] args) { UserDao userDao = new UserDaoImpl(); UserProxy userProxy = new UserProxy(userDao); userProxy.saveUser(); } }新创建一个用户实现类 (UserDaoImpl),它不执行用户操作。然后再创建一个用户代理(UserProxy),执行用户代理的用户保存(saveUser),其内部会调用用户实现类的保存用户(saveUser)方法,因为我们 JVM 可以在编译期确定最终的执行方法,所以上面的这种代理模式又叫做静态代理。
代理模式具有无侵入性的优点,以后我们增加什么新功能的话,我们可以直接增加一个代理类,让代理类来调用用户操作,这样我们就实现了不通过改源码的方式增加了新的功能。然后生活很美好了,我们能够直接添加我们想要的功能,在这美丽的日子里,cxuan 添加了用户代理、日志代理等等无数个代理类。但是好景不长,cxuan 发现每次改代码的时候都要改每个代理类,这就很烦啊!我宝贵的时光都浪费在改每个代理类上面了吗?
动态代理 JDK 动态代理