设计模式之动态代理

谁借莪1个温暖的怀抱¢ 2022-08-31 12:20 282阅读 0赞

1 背景回顾

设计模式是一种思维方式,前人总结的最佳实践,也是一种态度,一种进步。
软件过程里面设计模式一共有23种,一般分为3类。即创建型,结构性型,行为型。其中:
****创建型5种: **** 解决了创建对象的烦恼
单例模式,工厂模式,抽象工厂模式,建造者模式,原型模式

结构性型7种: 解决了如何让类组合起来完成复杂的功能
适配器模式,桥接模式,装饰模式,组合模式,外观模式,享元模式,代理模式,

行为型11种: 解决了类之间的控制关系。
模版方法模式,命令模式,迭代器模式,观察者模式,中介者模式,备忘录模式,状态模式,策略模式,职责链模式,访问者模式,解释器模式。

如果想要学习并掌握这些设计模式,最好是编码和画图理解

设计模式是一种思维方式,前人总结的最佳实践,也是一种态度,一种进步。
软件过程里面设计模式一共有23种,一般分为3类。即创建型,结构性型,行为型。其中:
**创建型5种: ** 解决了创建对象的烦恼
单例模式,工厂模式,抽象工厂模式,建造者模式,原型模式

结构性型7种: 解决了如何让类组合起来完成复杂的功能
适配器模式,桥接模式,装饰模式,组合模式,外观模式,享元模式,代理模式,

行为型11种: 解决了类之间的控制关系。
模版方法模式,命令模式,迭代器模式,观察者模式,中介者模式,备忘录模式,状态模式,策略模式,职责链模式,访问者模式,解释器模式。

如果想要学习并掌握这些设计模式,最好是编码和画图理解。

在学习动态代理之前,最好先学习静态代理,可以看笔者另外一篇基础文章:设计模式之静态代理

2 动态代理

因为静态代理对每个要被代理的类,都要创建一个对应的类,比较麻烦。由此,提出了动态代理,即一个代理可以代理多个真实的类。
需要用到3个类,InvokerHanlder接口,Proxy,前者要使用invoke方法,后者完成生成对应真实类的代理。

2.1 要代理的接口
租房

  1. package demo03;
  2. public interface Rent {
  3. void rent();
  4. }

2.2 真实的角色:房东

  1. package demo03;
  2. public class Host implements Rent {
  3. public void rent() {
  4. System.out.println("房东要租房");
  5. }
  6. }

2.3实现InokerHanlder接口

第一步: 定义被代理的接口
第二步:生成得到代理,通过Proxy.newProxyInstance(ClassLoader,Interfaces,InvokerHanlder),参数分别分类加载器,接口对象,InvokerHanlder
第三步:处理代理实例,并返回结果

  1. package demo03;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. //代理 调用处理器
  6. public class ProxyInvocationHandler implements InvocationHandler {
  7. // 1 定义被代理的接口
  8. private Rent rent;
  9. public void setRent(Rent rent) {
  10. this.rent = rent;
  11. }
  12. //2 生成得到代理
  13. public Object getProxy(){
  14. return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
  15. }
  16. //3 处理代理实例,并返回结果
  17. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  18. Object result = method.invoke(rent, args);//类似于,rent.method(args)
  19. return result;
  20. }
  21. }

2.4 客户端找代理

  1. package demo03;
  2. public class Client {
  3. public static void main(String[] args) {
  4. //需要先生成一个真实代理的类
  5. Rent host = new Host();
  6. //代理角色, 现在没有
  7. ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
  8. //通过调用处理角色来处理我们要调用的接口对象
  9. proxyInvocationHandler.setRent(host);
  10. // 动态生成代理
  11. Rent proxy = (Rent) proxyInvocationHandler.getProxy();
  12. proxy.rent();
  13. }
  14. }

执行结果:
在这里插入图片描述

3 动态代理进阶

对与第3个角色生成,可以写成一个通用工具类,以后使用时直接用就好了,即达到可以代理很多对象的初衷。

即把Rent接口变为Object就可以了。这个工具类可以代理很多类型对象。

  1. package demo04;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. //代理 调用处理器
  6. public class ProxyInvocationHandler implements InvocationHandler {
  7. // 1 定义被代理的接口
  8. private Object target;
  9. public void setRent(Object target) {
  10. this.target = target;
  11. }
  12. //2 生成得到代理
  13. public Object getProxy(){
  14. return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
  15. }
  16. //3 处理代理实例,并返回结果
  17. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  18. // 方法执行前
  19. Object result = method.invoke(target, args);//类似于,rent.method(args)
  20. // 方法执行后
  21. return result;
  22. }
  23. }

同时,在方法执行前后还能加一些方法:

  1. // 方法执行前
  2. Object result = method.invoke(target, args);//类似于,rent.method(args)
  3. // 方法执行后

具体如下:

  1. package demo04;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. //代理 调用处理器
  6. public class ProxyInvocationHandler implements InvocationHandler {
  7. // 1 定义被代理的接口
  8. private Object target;
  9. public void setRent(Object target) {
  10. this.target = target;
  11. }
  12. //2 生成得到代理
  13. public Object getProxy(){
  14. return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
  15. }
  16. //3 处理代理实例,并返回结果
  17. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  18. before();
  19. Object result = method.invoke(target, args);//类似于,rent.method(args)
  20. after();
  21. return result;
  22. }
  23. public void before(){
  24. System.out.println("==========invoke方法执行前======");
  25. }
  26. public void after(){
  27. System.out.println("=====invoke方法执行后=====");
  28. }
  29. }

执行结果:
在这里插入图片描述
接口里面如果有多个方法,在使用proxy.xxx()执行前后都会打印出来,这就是AOP的底层。

发表评论

表情:
评论列表 (有 0 条评论,282人围观)

还没有评论,来说两句吧...

相关阅读

    相关 java设计模式动态代理

    前言 为了更好的理解代理模式,首先根据生活中实际场景进行模拟,让我们在生活中去体验设计思想的美妙。 场景描述 “病从口入”这句成语告诉我们注意饮食健康,小六同学想