文章目录

  • 一、动态代理概述
    • 1.1 代理的概述和作用
    • 1.2 动态代理的优点
    • 1.3 代理对象的创建
    • 1.4 代理对象调用方法的执行流程
  • 二、动态代理举例
    • 2.1 歌手经纪人
    • 2.2 业务功能的性能统计
    • 2.3 动态代理在 Spring 框架中的应用
  • 三、基于子类的动态代理

一、动态代理概述

1.1 代理的概述和作用

  • 什么是代理?
    代理指某些场景下对象会找一个代理对象,来辅助自己完成一些工作。如:歌星(经济人),买房的人(房产中介)

  • 代理主要干什么工作,是如何工作的?
    是对对象的行为做一些辅助的操作。

  • 代理举例:
    歌手刚出道时,有人花钱让他唱歌,承诺先付首款再付尾款。那么,歌手的整个工作的流程是:收首款、唱歌、收尾款。
    歌手成名以后,业务越来越多,开始雇佣了经纪人。经纪人主要负责:收首款、收尾款以及调用歌手去唱歌,歌手只负责唱歌。


1.2 动态代理的优点

  • 非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为接本身做代理。
  • 可以为被代理对象的所有方法做代理。
  • 不仅简化了编程工作、提高了软件系统的可扩展性,同时也提高了开发效率。
  • 可以在不改变方法源码的情况下,实现对方法功能的增强。
    方法增强的理解:歌手原本的工作是唱歌,唱歌前后的收首款和尾款方法就相当于对原本的方法的增强。

1.3 代理对象的创建

  • java 中代理的代表类是: java.lang.reflect.Proxy

  • Proxy 提供了一个静态方法,用于为对象产生一个代理对象返回。


    参数二理解:因为客户是通过代理对象去调用歌手的唱歌方法,因此代理类需要接口的列表。


1.4 代理对象调用方法的执行流程

  1. 先走向代理
  2. 代理可以为方法额外做一些辅助工作
  3. 开发真正触发对象的方法的执行
  4. 回到代理中,由代理负责返回结果给方法的调用者

二、动态代理举例

2.1 歌手经纪人

项目包结构:

技能接口:

public interface Skill {void jump();void sing();
}

明星类:

public class Star implements Skill{private String name;public Star(String name) {this.name = name;}@Overridepublic void jump() {System.out.println(name + "开始跳舞");}@Overridepublic void sing() {System.out.println(name + "开始唱歌");}
}

明星代理类:

public class StarAgentProxy {/*** 设计一个方法来返回 一个明星对象 的 代理对象*      参数一:定义代理类的类加载器*      参数二:代理类要实现的接口列表*      参数三:将方法调用分派到的处理程序*/public static Skill getProxy(Star obj){// 为张三这个对象,生成代理对象return (Skill) Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("收首款");// proxy 代理对象的引用// method 正在调用的方法对象// args 代表这个方法的参数Object rs = method.invoke(obj, args); // 采用反射机制,如果没有返回值,则返回nullSystem.out.println("收尾款");return rs;}});}
}

客户端模拟:

public class Test {/*** 理解动态代理*/public static void main(String[] args) {// 1. 创建一个对象Star star = new Star("张三");// 为张三对象,生成一个代理对象(经纪人)Skill proxy = StarAgentProxy.getProxy(star);proxy.jump();System.out.println("--------");proxy.sing();}
}

输出结果:


2.2 业务功能的性能统计

需求: 模拟某企业用户管理业务,需包含用户登录、删除、查询功能,并要统计每个功能的耗时

项目包结构:

用户业务层接口:

public interface UserService {String login(String loginName, String password);void delete(Integer id);void selectUsers();
}

用户业务层实现类:

public class UserServiceImpl implements UserService{@Overridepublic String login(String loginName, String password) {String rs = "登录名称或者密码错误!";if("admin".equals(loginName) && "123456".equals(password)){rs = "登录成功";}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}return rs;}@Overridepublic void delete(Integer id) {try {System.out.println("正在删除数据中");Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}@Overridepublic void selectUsers() {System.out.println("查询了100个用户数据!");try {Thread.sleep(3000);} catch (Exception e) {e.printStackTrace();}}
}

代理对象工具类:

public class ProxyUtil {/*** 通过静态方法为用户业务对象返回代理对象*/public static UserService getProxy(UserService obj){return (UserService) Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {long startTime = System.currentTimeMillis();// 真正触发对象的行为执行Object rs = method.invoke(obj, args);long endTime = System.currentTimeMillis();System.out.println(method.getName() + "方法耗时:" + (endTime-startTime)/1000.0 + "s");return rs;}});}
}

客户端模拟:

public class Test {public static void main(String[] args) {UserService proxy = ProxyUtil.getProxy(new UserServiceImpl());proxy.login("admin", "123456");proxy.delete(1);proxy.selectUsers();}
}

输出结果:


2.3 动态代理在 Spring 框架中的应用

转账方法的事务问题回顾:

参考:Spring 从入门到精通系列 09 —— 转账方法的事务问题与动态代理

转账业务流程中,如果中间的某一部分业务出现异常,那么会导致异常后的事务不会执行,从而引发账户出错的严重情况。


问题的关键在于:
整个业务方法一共获取了四次数据库连接对象,有四个业务需要处理。当前事务完成后,会直接提交事务。那么当某个事务出现异常时,只对他自己的事务进行回滚,对其他的事务不回滚。

当时提出的解决方案是:
由于整体的业务属于一个线程,那么通过使用 ThreadLocal 对象把 Connection 连接对象和当前线程绑定,即使一个线程中只有一个 Connection 对象,而不是原本的四个。(要么都发生,要么都不发生)

更新事务控制后,具体实现如下:


代码变的很复杂,而且每个方法都需要加上:开启事务、提交事务…等事务处理。因此,可利用动态代理的技术进行处理。
Spring 的 AOP 的实现思想就是动态代理,即 在不修改源码的基础上对已有方法进行增强。


三、基于子类的动态代理

上文讲述的代理模式属于 基于接口的动态代理模式,当其不实现任何接口时,该动态代理对象不能得到。
但是 基于子类的动态代理 可以实现不用实现接口的情况下实现代理。

导入依赖:

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.1_3</version>
</dependency>

明星类:

public class Star{private String name;public Star() {}public Star(String name) {this.name = name;}public void jump() {System.out.println(name + "开始跳舞");}public void sing() {System.out.println(name + "开始唱歌");}
}

明星代理类:

public class ProxyUtil {/*** 通过静态方法为用户业务对象返回代理对象*/public static Star getProxy(Star obj){return (Star) Enhancer.create(obj.getClass(), new MethodInterceptor() {/*** 执行被代理对象的任何方法都会经过该方法* @param proxy* @param method* @param args*    以上三个参数和基于接口的动态代理中invoke方法的参数是一样的* @param methodProxy :当前执行方法的代理对象*/@Overridepublic Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {System.out.println("收首款");Object rs = method.invoke(obj, args);System.out.println("收尾款");return rs;}});}
}

客户端模拟:

public class Test {public static void main(String[] args) {final Star star = new Star("张三");Star proxy = ProxyUtil.getProxy(star);proxy.jump();System.out.println("--------");proxy.sing();}
}

输出结果:

注:基于子类的动态代理,被代理类必须实现无参构造(当被代理类中有参构造函数时,需重写无参构造),否则报以下异常。

软件设计模式 | 动态代理模式相关推荐

  1. Android开发中无处不在的设计模式——动态代理模式

    继续更新设计模式系列.写这个模式的主要原因是近期看到了动态代理的代码. 先来回想一下前5个模式: - Android开发中无处不在的设计模式--单例模式 - Android开发中无处不在的设计模式-- ...

  2. 研磨23种大话设计模式------动态代理模式 + 小结静态代理模式

    大家好,我是一位在java学习圈中不愿意透露姓名并苟且偷生的小学员,如果文章有错误之处,还望海涵,欢迎多多指正 如果你从本文 get 到有用的干货知识,请帮忙点个赞呗,据说点赞的都拿到了offer 在 ...

  3. 【设计模式】代理模式 ( 动态代理 | 模拟 Java 虚拟机生成对应的 代理对象 类 )

    文章目录 前言 一.模拟 JVM 生成对应的 代理对象 二.模拟 JVM 生成对应的 代理对象 完整流程展示 1.目标对象接口 2.被代理对象 3.调用处理程序 4.模拟 JVM 生成的代理对象类 5 ...

  4. 设计模式之代理模式、动态代理模式、Cglib代理模式

    代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能. 这里使用到编程中的 ...

  5. 【设计模式】--- 装饰器模式、静态代理模式和动态代理模式

    文章目录 1 引子 2 业务场景介绍 3 静态代理模式 4 装饰器模式 5 动态代理模式 5.1 Proxy --- 具体的代理对象生成组件 5.2 InvocationHandler --- 封装被 ...

  6. 设计模式之----Java动态代理模式

    在Spring中,有很多设计模式被应用,其中不乏代理模式.而代码模式中,就一定少不了动态代理模式.今天就对动态代理模式进行学习记录. 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托 ...

  7. Java设计模式之JDK动态代理模式

    先来谈谈什么动态代理模式,在一家软件公司,假如你是一个软件开发工程师.当客户带着需求去找公司的时候,显然不会直接让你和客户谈,肯定是先和商务经理,产品经理类的谈需求.因为客户的需求可能千奇百怪,很有可 ...

  8. 设计模式之动态代理模式实战

    昨天分享了静态代理的概念及存在的缺点,所以今天讲的动态代理模式十分重要.动态代理在我们工作当中应用相当广泛,如Srping AOP就是动态代理的在开源框架的比较出名的应用. 动态代理有两种试,一是通过 ...

  9. 23种设计模式之代理模式(动态代理)

    代理模式 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 代理模式的组成 抽 ...

最新文章

  1. [原创]Gerrit中文乱码问题解决方案分享
  2. 一次OGG ERROR OGG-01091 Unable to open file ./dirdat/th079817 的问题解决
  3. OpenCV人脸检测并把图片写成avi视频
  4. dedecms模版php,dedecms专题模板怎么用
  5. 快速掌握:大型分布式系统中的缓存架构
  6. C++ 获取URL图片、html文件,CInternetSession 【转】
  7. 国产数据库助力民航核心交易系统
  8. 网易云API服务搭建
  9. matlab里面计算相关系系数的显著性,数学建模笔记——相关系数
  10. 粤语翻译软件开发_粤语翻译器 带发音-粤语翻译器 带发音免费软件app安卓v2.3下载-SLY软件园...
  11. 天马行空脚踏实地,阿里巴巴有群百里挑一的天才应届生...
  12. 小米 10s fastboot下 刷入 rec
  13. 在3D城市模型中添加不同的纹理
  14. order by排序出现问题
  15. 在线工具:将图片透明化
  16. 软件测试面试总被拒怎么办?表姐把压箱底的面试秘籍交给了我,现在已经在上班了。
  17. python图表制作方法_Python中一种简单的动态图表制作方法
  18. 破解网吧管理软件各类限制的几点小技巧
  19. 惊喜开学季,教你如何在人工智能时代站稳脚跟!
  20. Panuon.UI.Silver – 开源C# WPF控件库

热门文章

  1. 切换环境,MTM能力,区分移动还是联通
  2. 二叉搜索树的后序遍历序列(Java)
  3. 紫光集团发布公有云战略 掘金企业级业务
  4. Java集成阿里云的实时语音识别遇到的一些问题
  5. C++创建People类--练习
  6. urllib之urlopen和urlretrieve的headers传入以及parse、urlparse、urlsplit的使用
  7. 多线程之哲学家就餐问题(java代码含注释)
  8. python pil 安装
  9. STM32 Ymodem 协议及代码解析
  10. 华为HCIE RS笔记-03数据封装