JAVA学习记录——代理模式
(记录时间2022-03-12)
(最近在学习java设计模式中的代理模式想着为了加深映像巩固一下,就写写博客记录一下,也当时记录一下自己的学习过程吧)
- 什么是代理模式?
代理模式的定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。其实也就是我们生活中很常见的中介,提供方提供事务由代理对象替提供方解决事务并且解决其中更多复杂的步骤。举个例子:例如当前有一个房东想租房,如果没有代理则需要房东自己找客源,要自己想办法进行各种进行各种促销和租个好价格等待一些麻烦的操作,介时咔咔咔中介登场由中介帮忙代理,房东只需要提供“我需要租房这个需求”这个事务然后便交由中介代理即可,中介来解决中间的麻烦步骤并且还能额外提供服务,比如促销活动的租房子送充电宝呀啥的(斯~好冷)到时房东只需要到时处理买房这个事务即可。这就是大概的代理模式的样子。
- 为什么要使用代理模式?
- 代理隔离作用:有时提供者并不善于或者无法接触需求对象,例如卖房的房东无法联系到需求对象导致房子难以卖出,又或者卖房的房东并不善于这种商业交际一不小心被别人骗得都倒贴钱了(介不是闹呢吗)。这时多出来的中间代理对象并可以利用自己的资源帮助提供方解决问题,例如中介有丰富的客源或者能说会道等等。这时提供方只需要知道自身事务而后则可把这个事务交由代理对象处理中间额外服务也不需要提供方了解和提供,但真正的事务还是由提供方处理,卖房还是要由房东进行处理而不能由代理方直接售出。总得来说代理方是向提供方提供服务的并不是起决定性作用的。自我理解来说,就是一种事务的隔离,不同事务交由不同对象去提供处理。提供方只需要提供资源和需求,代理方只需要负责如何处理这些需求和提供服务,各司其职。
- 符合开闭原则,额外类提供功能:对修改关闭,对扩展开发。事务类和事务接口只需要提供对应的事务处理方法,然后便可把事务对象实例交由代理类进行调用处理,代理类依旧是调用事务类提供的方法,不过可以再这些方法的基础上提高额外的更好的服务,这便也可以在不修改原事务类代码的情况下扩展提高更多的服务处理。例如对事务的日志记录和持久化处理等等真正的事务还是由事务类进行处理。
- 两种代理模式的实现方式
代理模式的实现很多接下来主要记录两种代理模式,静态代理模式和动态代理模式。(为什么就说这两种呢,因为.....其他的我不会(无奈摊手))
- 静态代理模式
由程序员对应每个业务提供对应代理类,例子:
首先要有一个业务接口和对应的接口实现类.
业务接口:
public interface host{ public void buyHome(); public void getmomey(); }
对应业务类实现:
public class hostImpl implements host { @Override public void buyHome() { System.out.println("卖房"); } @Override public void getmomey() { System.out.println("收钱"); } }
这时不用业务类直接与需求对象进行直面“交流”,将事务交由代理类代理,由代理类处理事务前后的一些服务和操作,实现业务和直接需求方的隔离并且还在代理类上进行功能扩展。
对应业务代理类:
public class houseProxy { private hostImpl host; public houseProxy(hostImpl host) { this.host = host; } public void service() { System.out.println("提供服务"); } public void buyHouse() { service(); host.buyHome(); host.getmomey(); System.out.println("售后服务"); } }
由代码可以看出在静态代理中一个代理类对应一个业务处理,实际的业务还是由业务实现类进行处理,但代理类可以对业务提供额外的服务。现在我们就有个疑问代理类有哪些优缺点呢
首先是优点:
-
- 代理类实现业务提供方和需求方的隔离
- 代理类在符合开放原则的基础上对事务进行扩展,并且还能使类的功能更加独立。
然后的缺点:
-
- 静态代理需要对每个业务都提供对应代理类,代码复用性较差,并且当业务较多时程序员工作量大
然后解决代码复用性差,并且在业务多时程序员工作量大的问题呢。这些便是接下来动态代理所能够解决的了
- 动态代理模式
还是和上面一样需要提供一个业务接口和业务实现类。动态代理是由反射机制动态生成类,并且使用方法拦截机制将每次方法调用拦截在Invocation类的invoke方法中,由程序决定后续处理。
首先动态代理模式的代理类需要实现Invocation接口。其中需要实现public Object invoke(Object proxy,Method method,Object args[])这个抽象方法
- proxy参数,代理对象
- method参数,被拦截的方法
- args[]参数,拦截的方法参数
实现类示例为:
public class AdminServiceInvocation implements InvocationHandler { private Object target;//实际代理对象 public AdminServiceInvocation(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("执行操作"); System.out.println(method.getName()); Object o=method.invoke(target,args); System.out.println("结束操作"); return o; } }
这里有一个需要注意的点,invoke中的method参数拦截的就是代理类调用的方法,使用在使用method对象的invoke方法是不能将proxy作为方法调用参数进行传入,invoke方法中有两个参数第一个是调用这个方法的实例类第二个是方法参数,如果调用的方法实例类为proxy会发生什么情况呢。我们上面说到的,invoke方法的method对象实际上就是被拦截的代理类方法而proxy便是哪个代理类,如果传入proxy就会导致这个方法调用再次被invoke方法拦截然后再次触发再次拦截....如果没有停止手段就成了没有停止条件的递归了,然后就嘿嘿嘿.a.a。所以一定要注意这一点。需要我们把代理类作为参数传到这个target对象中,当代理类作为参数传入时target实例便是一个代理类的拷贝而不是原本的代理类便可以避免这种情况的出现(equlas方法返回值为false,但具体啥情况并不太情况,因为他们的hash码是相同的但是equlas却false,很迷,欢迎大佬们指出)。
上述我们说过了动态代理由反射动态生成代理对象,那么怎么生成呢?
这时我们就需要Proxy类滴static Object
newProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h)方法
- loader参数:需要代理类的类加载器。
- interfaces参数:业务类接口,所以动态代理需要业务类有业务接口。
- h参数:InvocationHandler接口实现类就是对应的方法拦截处理类,会将所有方法都拦截到这个参数的invoke方法中继续后续处理。
示例为:
public class staticHostProxy { private Object target; private InvocationHandler invocationHandler; public staticHostProxy(Object target, InvocationHandler invocationHandler) { this.target = target; this.invocationHandler = invocationHandler; } public Object getProxy() { Object o = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), invocationHandler); return o; } }
返回的Object实例便是代理类对象,需要进行强转操作。
因为动态代理都会将所有方法拦截到invoke方法中如果要用同一种代理对象处理多个业务就需要考虑invoke方法中的方法能否对这些业务都适用。
当然动态代理需要要求类一定要有接口,那么没接口的对象呢,那么就是CGLIB代理模式但是...我不会..
这便是目前我所了解的两种代理模式,欢迎大佬来指正和交流,随时欢迎共同学习。
(这是我的第一篇博客如果有啥需要改正和改进的地方欢迎大家指正,谢谢大家)
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)