一.代理模式的概念

即Proxy Pattern,23种常用的面向对象软件的设计模式之一。

代理模式的定义:

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,因此创建代理对象,代理对象在客户端和目标对象之间起到中介的作用。

代理模式的组成部分:

代理模式使用三个角色实现其目标功能,分别是:
抽象角色(AbstractRole):
通过接口或抽象类声明真实角色实现的业务方法。
代理角色(ProxyRole):
实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
真实角色(RealRole):
实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

代理模式分类:

代理模式根据其实现方法的不同分为动态代理和静态代理,静态代理和动态代理的主要区别在于其生成代理类的方式,静态代理由程序员直接编写代理类,而动态代理的代理类是在程序执行过程中生成的

二.静态代理

静态代理根据代理类的生成方式分为聚合式静态代理和继承式静态代理
聚合式静态代理中代理类和目标类都实现了同一个接口,又称为代理类聚合了目标类,可实现灵活多变
继承式静态代理中代理类继承了目标类,减少了代码量(不必对不进行功能扩展的方法进行覆盖),但是不够灵活

2.1 聚合式静态代理示例:

该程序由4部分组成:

接口:抽象角色(AbstractRole)

public interface IUserDao {void save();void find();
}

目标类:即真实角色(RealRole)

public class UserDao implements IUserDao{@Overridepublic void save() {System.out.println("模拟: 保存用户!");}@Overridepublic void find() {System.out.println("查询");}
}

代理类:代理角色(ProxyRole)
由程序员根据需要(扩展功能)编写

public class UserDaoProxy implements IUserDao{//代理对象,需要维护一个目标对象private IUserDao target = new UserDao();//代理对象对目标对象进行功能扩展,使得代理对象能够完成目标对象不能完成的任务@Overridepublic void save() {System.out.println("代理操作: 开启事务...");target.save();System.out.println("代理操作:提交事务...");}//不需要进行功能扩展的方法则直接调用目标对象中对应的该方法@Overridepublic void find() {target.find();}
}

测试方法:

public class Application {public static void main(String[] args) {//创建代理对象IUserDao proxy = new UserDaoProxy();proxy.find(); proxy.save(); }
}

程序执行结果:

代理类UserDaoProxy扩展了目标类UserDao的功能,增强了save( )方法的功能,原本save( )方法只输出一句话,进行功能增强后多输出了两句话

2.1 继承式静态代理示例:

该程序由3部分组成:不需要接口即抽象角色(AbstractRole)

目标类:即真实角色(RealRole)

public class UserDao {@Overridepublic void save() {System.out.println("模拟: 保存用户!");}@Overridepublic void find() {System.out.println("查询");}
}

代理类:代理角色(ProxyRole)
由程序员编写

public class UserDaoProxy extends UserDao{//代理对象对目标对象进行功能扩展@Overridepublic void save() {System.out.println("代理操作: 开启事务...");target.save();System.out.println("代理操作:提交事务...");}
}

测试方法:

public class Application {public static void main(String[] args) {//创建代理对象IUserDao proxy = new UserDaoProxy();proxy.find(); proxy.save(); }
}

继承式静态代理实现的功能和聚合式静态代理相同

三.动态态代理

动态代理中的代理类是在程序执行过程中生成的,而不是由程序员直接编写的
动态代理根据代理类生成方法的不同分为JDK动态代理和cglib动态代理,和静态代理中聚合式与继承式的分类相同,JDK动态代理中代理类和目标类都实现了同一个接口,cglib动态代理中代理类则继承了目标类

3.1 JDK动态代理

JDK动态代理主要使用了反射技术,同时还要用到JavaSE中的Proxy类和InvocationHandler接口

3.1.1 动态代理涉及的类和接口

1)Proxy类

Proxy类在reflect包下,与反射的关系紧密
Proxy类中的方法:

其中第4个方法newProxyInstance( )最常用,用来创建代理类,其三个参数分别为(1)一个类加载器,(2)代理类和目标类共同实现的接口,(3)一个实现了InvocationHandler接口的对象

2)InvocationHandler接口

InvocationHandler接口的主要用途就是作为Proxy类的newProxyInstance( )方法的参数,用来创建代理对象。其有4个实现类
InvocationHandler接口只有一个invoke( )方法

3.1.2 动态代理示例:

下面展示一个静态代理程序,和静态代理一样,由4部分组成:

接口:抽象角色(AbstractRole)

//和静态代理一样,没有更改
public interface IUserDao {void save();void find();
}

目标类:即真实角色(RealRole)

//和静态代理一样,没有更改
public class UserDao implements IUserDao{@Overridepublic void save() {System.out.println("模拟: 保存用户!");}@Overridepublic void find() {System.out.println("查询");}
}

代理类:代理角色(ProxyRole)
动态代理中,代理类是由程序生成的,这时不直接编写代理类,而是编写一个专门生成代理类的工厂类ProxyFactory,由ProxyFactory根据传入的参数生成代理类
ProxyFactory

public class ProxyFactory {//构造方法,接收一个目标对象private Object target;public ProxyFactory(Object target) {this.target = target;}//代理对象的创建方法public Object getProxyInstance() {//调用Proxy类的newProxyInstance()方法Object proxy = Proxy.newProxyInstance(//参数一:目标对象使用的类加载器target.getClass().getClassLoader(),  //参数二:目标对象实现的所有接口target.getClass().getInterfaces(),   //参数三:一个InvocationHandler对象的实现类,这里使用适配器模式创建//执行代理对象方法时才执行此方法,创建代理对象是不执行此方法new InvocationHandler() {           @Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//获取当前执行的方法的方法名String methodName = method.getName();//方法返回值Object result = null;//判断程序调用的代理类的方法if ("find".equals(methodName)) {//不需要进行功能扩展的方法,反射创建目标类的方法并调用result = method.invoke(target, args);} //需要进行功能扩展的方法else {//进行功能扩展System.out.println("开启事务...");//反射创建目标类的方法并调用result = method.invoke(target, args);System.out.println("提交事务...");  }//返回结果return result;}});return proxy;}
}

测试方法:

public class Application {public static void main(String[] args) {    //创建目标对象IUserDao target = new UserDao();System.out.println("目标对象:" + target.getClass());  // class cn.itcast.b_dynamic.UserDao//创建代理对象,使用代理工厂IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();System.out.println("代理对象: " + proxy.getClass());  //  class $Proxy0//执行代理对象的方法proxy.find();proxy.save();}
}

程序执行结果:

3.2 cglib动态代理

JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类,就需要使用cglib实现
cglib是一个强大的,高性能,高质量的code生成类库,它可以在运行期通过生成代理对象的方式扩展目标类的功能,它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)
cglib包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉

目标类:即真实角色(RealRole)

public class UserDao {public static void save() {System.out.println("模拟: 保存用户!");}public void find() {System.out.println("查询");}
}

代理类:代理角色(ProxyRole)

public class ProxyFactory implements MethodInterceptor{//接收一个目标对象private Object target;public ProxyFactory(Object target) {this.target = target;}//返回代理对象——一个目标对象的子类对象public Object getProxyInstance() {//字节码生成工具类Enhancer en = new Enhancer();//设置父类en.setSuperclass(target.getClass());//设置回调函数en.setCallback(this);//创建子类对象return en.create();}// 事件处理器,执行目标方法时候执行@Overridepublic Object intercept(Object obj, Method method, Object[] args,MethodProxy methodProxy) throws Throwable {System.out.println("开启事务...");Object result = method.invoke(target, args);System.out.println("提交事务...");return result;}
}

测试方法:

public class App {public static void main(String[] args) {//创建目标对象UserDao target = new UserDao();System.out.println("目标对象:" + target.getClass());//创建代理对象UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance();System.out.println("代理对象: " + proxy.getClass());//执行代理对象的方法proxy.find();proxy.save();}
}

总结:

经过静态代理和动态代理实现方法的分析,可以看出动态代理的优势:如果对多个目标类进行同样的功能扩展,使用静态代理需要为每个目标类创建一个代理对象,耦合性非常高,可复用性非常低,而使用动态代理,则只需要创建一个代理工厂,代理对象可以用代理工厂创建,这样扩展功能只需编写一遍就可以对所有目标类进行功能扩展

Java设计模式--代理模式与JDK动态代理,cglib动态代理相关推荐

  1. java中的静态、动态代理模式以及Spring中的CgLib动态代理解读(面试必问)

    java中的静态.动态代理模式以及Spring中的CgLib动态代理解读(面试必问) 静态代理 动态代理 CgLib动态代理     基础知: 反射知识 代理(Proxy)是一种设计模式,提供了对目标 ...

  2. 设计模式-代理模式(jdk代理和cglib代理详解)

    说起代理模式,相信很多人早已经很理解,但对于我这个菜鸟,理解的可能还是不到位,写一次博客加深印象. 什么是代理模式呢?代理模式是常用的Java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要 ...

  3. 【设计模式】代理模式之JDK动态代理与CGLIb代理区别

    一.什么是代理? 代理模式是Java中常见的一种模式,英文名字叫走Proxy或者Surrogate,代理的本意是一个人代表另一个人,或者一个机构代表另一个机构,采取行动,因而,代理和现实生活中的中介有 ...

  4. 【java项目实战】代理模式(Proxy Pattern),静态代理 VS 动态代理

    这篇博文,我们主要以类图和代码的形式来对照学习一下静态代理和动态代理.重点解析各自的优缺点. 定义 代理模式(Proxy Pattern)是对象的结构型模式,代理模式给某一个对象提供了一个代理对象,并 ...

  5. Java设计模式 -11- 外观模式(Facade模式)

    Java设计模式 -11- 外观模式(Facade模式) 前言 外观模式的定义与特点 优点: 缺点: 外观模式的结构与实现 1. 模式的结构 2. 模式的实现 外观模式的应用实例 外观模式的应用场景 ...

  6. java设计模式迭代器模式_迭代器设计模式示例

    java设计模式迭代器模式 本文是我们名为" Java设计模式 "的学院课程的一部分. 在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们. 您将了解模式 ...

  7. java设计模式迭代器模式_Java中的迭代器设计模式–示例教程

    java设计模式迭代器模式 迭代器模式是一种行为模式,它用于提供遍历一组对象的标准方式. Iterator模式在Java Collection Framework中得到了广泛使用,其中Iterator ...

  8. java设计模式工厂模式_Java中的工厂设计模式

    java设计模式工厂模式 Welcome to the Factory Design Pattern in Java tutorial. Factory Pattern is one of the C ...

  9. java设计模式迭代器模式_Java中的迭代器设计模式

    java设计模式迭代器模式 Iterator design pattern in one of the behavioral pattern. Iterator pattern is used to ...

  10. Java设计模式-策略模式作业

    Java设计模式-策略模式作业,所有类和接口均在一个package内 文章目录 前言 一.作业内容 二.具体实现 1.类图 2.Strategy接口 3.PreCopyStrategy类 4.Post ...

最新文章

  1. JS格式化JSON串显示在表格中
  2. PIL image.fromarray()函数
  3. LeetCode:棒球比赛【682】
  4. 微信墙服务器地址,一面微信墙的诞生(3) 用户端界面的创建
  5. python中函数分为哪四类_Python函数参数分类原理详解
  6. SQL基础:数据表的创建
  7. 【手撸一个ORM】第八步、查询工具类
  8. 邻居家小孩来问WiFi密码,告诉后邻居家竟然几部手机电视全用上,该怎么办?
  9. CSS中min-height:100%问题
  10. 如何快速入门LABVIEW及数据采集
  11. 中国通信业:那些年,我们给用户挖的坑
  12. Amos24程序安装及注意事项
  13. 微信Web APP应用
  14. Exchange邮箱的创建和配置
  15. Docker实战-部署GPE微服务的监控体系(二)
  16. UCAS计算机网络实验
  17. Cow Tennis Tournament
  18. 一个简单的三子棋游戏
  19. 超越前端Beyond Frontend — 吉密斯/gMIS 增加点选/PickUp概览功能
  20. 给你好“See” 2018链圈迎来“深水炸弹”?

热门文章

  1. HighCharts:设置饼图不可点击选择
  2. Javascript特效:字体背景跑马灯
  3. 随手记_搞科研怎样读论文
  4. CLION CMAKE 缺-g 导致断点不执行(无效)
  5. Huffman树概念及理解
  6. YOLOv4中的数据增强
  7. 最长回文子串问题:给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
  8. WebLogic 11g重置用户密码
  9. Spring Cloud(8):Sleuth和Zipkin的使用
  10. Ubuntu16.04 安装显卡驱动 cuda,cudnn