Java动态代理之JDK实现和CGlib实现(简单易懂)

转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6542259.html

一:代理模式(静态代理)

代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理。

静态代理由 业务实现类、业务代理类 两部分组成。业务实现类 负责实现主要的业务方法,业务代理类负责对调用的业务方法作拦截、过滤、预处理,主要是在方法中首先进行预处理动作,然后调用业务实现类的方法,还可以规定调用后的操作。我们在需要调用业务时,不是直接通过业务实现类来调用的,而是通过业务代理类的同名方法来调用被代理类处理过的业务方法。

静态代理的实现:

1:首先定义一个接口,说明业务逻辑。

    package net.battier.dao;      /** * 定义一个账户接口 * @author Administrator*/  public interface Count {  // 查询账户public void queryCount();  // 修改账户  public void updateCount();  }  

2:然后,定义业务实现类,实现业务逻辑接口

import net.battier.dao.Count;
/** * 委托类(包含业务逻辑) *  * @author Administrator *  */
public class CountImpl implements Count {  @Override  public void queryCount() {  System.out.println("查看账户...");  }  @Override  public void updateCount() {  System.out.println("修改账户...");  }  }  

3:定义业务代理类:通过组合,在代理类中创建一个业务实现类对象来调用具体的业务方法;通过实现业务逻辑接口,来统一业务方法;在代理类中实现业务逻辑接口中的方法时,进行预处理操作、通过业务实现类对象调用真正的业务方法、进行调用后操作的定义。

public class CountProxy implements Count {  private CountImpl countImpl;  //组合一个业务实现类对象来进行真正的业务方法的调用/** * 覆盖默认构造器 *  * @param countImpl */  public CountProxy(CountImpl countImpl) {  this.countImpl = countImpl;  }  @Override  public void queryCount() {  System.out.println("查询账户的预处理——————");  // 调用真正的查询账户方法countImpl.queryCount();  System.out.println("查询账户之后————————");  }  @Override  public void updateCount() {  System.out.println("修改账户之前的预处理——————");  // 调用真正的修改账户操作countImpl.updateCount();  System.out.println("修改账户之后——————————");  }  }  

4:在使用时,首先创建业务实现类对象,然后把业务实现类对象作构造参数创建一个代理类对象,最后通过代理类对象进行业务方法的调用。

 public static void main(String[] args) {  CountImpl countImpl = new CountImpl();  CountProxy countProxy = new CountProxy(countImpl);  countProxy.updateCount();  countProxy.queryCount();  }  

静态代理的缺点很明显:一个代理类只能对一个业务接口的实现类进行包装,如果有多个业务接口的话就要定义很多实现类和代理类才行。而且,如果代理类对业务方法的预处理、调用后操作都是一样的(比如:调用前输出提示、调用后自动关闭连接),则多个代理类就会有很多重复代码。这时我们可以定义这样一个代理类,它能代理所有实现类的方法调用:根据传进来的业务实现类和方法名进行具体调用。——那就是动态代理。

二:动态代理的第一种实现——JDK动态代理

  JDK动态代理所用到的代理类在程序调用到代理类对象时才由JVM真正创建,JVM根据传进来的 业务实现类对象 以及 方法名 ,动态地创建了一个代理类的class文件并被字节码引擎执行,然后通过该代理类对象进行方法调用。我们需要做的,只需指定代理类的预处理、调用后操作即可。

1:首先,定义业务逻辑接口

public interface BookFacade {  public void addBook();
} 

2:然后,实现业务逻辑接口创建业务实现类

public class BookFacadeImpl implements BookFacade {   @Override  public void addBook() {  System.out.println("增加图书方法。。。");  }  } 

3:最后,实现 调用管理接口InvocationHandler  创建动态代理类

public class BookFacadeProxy implements InvocationHandler {  private Object target;//这其实业务实现类对象,用来调用具体的业务方法 /** * 绑定业务对象并返回一个代理类  */  public Object bind(Object target) {  this.target = target;  //接收业务实现类对象参数//通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用//创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类return Proxy.newProxyInstance(target.getClass().getClassLoader(),  target.getClass().getInterfaces(), this); }  /** * 包装调用方法:进行预处理、调用后处理 */  public Object invoke(Object proxy, Method method, Object[] args)  throws Throwable {  Object result=null;  System.out.println("预处理操作——————");  //调用真正的业务方法  result=method.invoke(target, args);  System.out.println("调用后处理——————");  return result;  }  }  

4:在使用时,首先创建一个业务实现类对象和一个代理类对象,然后定义接口引用(这里使用向上转型)并用代理对象.bind(业务实现类对象)的返回值进行赋值。最后通过接口引用调用业务方法即可。(接口引用真正指向的是一个绑定了业务类的代理类对象,所以通过接口方法名调用的是被代理的方法们)

public static void main(String[] args) {  BookFacadeImpl bookFacadeImpl=new BookFacadeImpl();BookFacadeProxy proxy = new BookFacadeProxy();  BookFacade bookfacade = (BookFacade) proxy.bind(bookFacadeImpl);  bookfacade.addBook();  }  

JDK动态代理的代理对象在创建时,需要使用业务实现类所实现的接口作为参数(因为在后面代理方法时需要根据接口内的方法名进行调用)。如果业务实现类是没有实现接口而是直接定义业务方法的话,就无法使用JDK动态代理了。并且,如果业务实现类中新增了接口中没有的方法,这些方法是无法被代理的(因为无法被调用)。

三:动态代理的第二种实现——CGlib

  cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。

1:首先定义业务类,无需实现接口(当然,实现接口也可以,不影响的)

public class BookFacadeImpl1 {  public void addBook() {  System.out.println("新增图书...");  }
}  

2:实现 MethodInterceptor方法代理接口,创建代理类

public class BookFacadeCglib implements MethodInterceptor {  private Object target;//业务类对象,供代理方法中进行真正的业务方法调用//相当于JDK动态代理中的绑定public Object getInstance(Object target) {  this.target = target;  //给业务对象赋值Enhancer enhancer = new Enhancer(); //创建加强器,用来创建动态代理类enhancer.setSuperclass(this.target.getClass());  //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦        enhancer.setCallback(this);        // 创建动态代理类对象并返回         return enhancer.create();     }    // 实现回调方法     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {         System.out.println("预处理——————");        proxy.invokeSuper(obj, args); //调用业务类(父类中)的方法        System.out.println("调用后操作——————");        return null;     } 

3:创建业务类和代理类对象,然后通过  代理类对象.getInstance(业务类对象)  返回一个动态代理类对象(它是业务类的子类,可以用业务类引用指向它)。最后通过动态代理类对象进行方法调用。

public static void main(String[] args) {      BookFacadeImpl1 bookFacade=new BookFacadeImpl1();BookFacadeCglib  cglib=new BookFacadeCglib();  BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(bookFacade);  bookCglib.addBook();  }  

四:比较

静态代理是通过在代码中显式定义一个业务实现类一个代理,在代理类中对同名的业务方法进行包装,用户通过代理类调用被包装过的业务方法;

JDK动态代理是通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法;

CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理;

转载于:https://www.cnblogs.com/zyzcj/p/7268957.html

转载 cglib代理和java代理相关推荐

  1. 八 web爬虫讲解2—urllib库爬虫—ip代理—用户代理和ip代理结合应用

    使用IP代理 ProxyHandler()格式化IP,第一个参数,请求目标可能是http或者https,对应设置 build_opener()初始化IP install_opener()将代理IP设置 ...

  2. ip模拟工具_HTTP代理和IP代理有什么区别

    在我们互联网工作者当中,HTTP代理和IP代理相信都不陌生.因为在大家工作的时候,一些特定的领域或者功能需要通过代理软件来完成.虽然这个软件不是一定要使用,可是一旦不用不仅会让工作效率变低,爬虫工作者 ...

  3. Socks5代理和IP代理

    Socks5代理和IP代理是常用的网络代理服务,它们为用户提供了匿名访问和保护隐私的功能.在本文中,我们将介绍这两种代理的基本概念和工作原理,并展示如何编写一个简单的代理服务器. 一.什么是Socks ...

  4. 详细的HTTP代理和SOCKS代理

    代理,也称为网络代理,是一种特殊的网络服务,它允许网络终端(通常是客户端)通过此服务与另一个网络终端(通常是服务器)进行间接连接.详细的HTTP代理和SOCKS代理 代理的主要目的是更改IP地址.市场 ...

  5. socks5代理和HTTP代理有什么区别呢?

    首先,让我们来了解一下什么是代理.代理是一种在网络中用于隐藏客户端真实IP地址的技术,它允许客户端通过中间代理服务器进行网络请求和响应.而代理服务器则会将客户端请求转发给目标服务器,接收到响应后再转发 ...

  6. HTTP代理和HTTPS代理的区别

    随着代理服务器的广泛使用,大家多少对这一工具有一些了解,今天我们就来看看HTTP代理和HTTPS代理的工作流程有哪些不同? HTTP协议即超文本传输协议,它的全称为Hyper Text Transfe ...

  7. http代理和SOCK5代理,我们在使用中选择哪一个,是不是HTTP是明码,不够安全?

    我们在选择代理IP时,会发现代理IP有各种各样的类型,什么长效代理IP.短效代理IP.普匿代理IP.高匿代理IP.动态代理IP等等,当然还有今天的主角,http代理IP和Socks代理IP.这其实是更 ...

  8. socks5代理和http代理流程

    代理分类 一.正向代理(forward proxy) 一般所说的代理就是正向代理,客户端使用正向代理时需要知道代理的IP和端口,并发送服务代理格式的请求.代理解析客户端的请求,获取服务器地址后建立连接 ...

  9. spring 如何决定使用jdk动态代理和cglib(转)

    Spring1.2: 将事务代理工厂[TransactionProxyFactoryBean] 或 自动代理拦截器[BeanNameAutoProxyCreator] 的 proxyTargetCla ...

最新文章

  1. Linux笔记:使用Vim编辑器
  2. HDLBits 系列(36)Arbitration circuit implemented by FSM
  3. python【蓝桥杯vip练习题库】ADV-186排列式
  4. python2.7安装pip_RobotFramework安装过程遇到的问题(电脑同时安装python2和3)
  5. HTML页面打印功能js代码,JavaScript_js实现页面打印功能实例代码(附去页眉页脚功能代码),复制代码 代码如下: html - phpStudy...
  6. 将cmd添加到鼠标右键,并且在任意目录下可以打开
  7. 图像语义分割(10)-DeepLabV3+: 用于图像语义分割的带有空洞可分离卷积的编解码结构
  8. 获得学士学位的机器学习工程工作
  9. 关于联想键盘,如何去除fn 键 联想官方解决方法
  10. Premiere CC2019软件下载和安装教程
  11. 【2021】【论文笔记】太赫兹量子阱光电探测器——
  12. 第三方支付接口现号,第三方支付接口对接,第三方支付接口申请
  13. 海康威视摄像头的多通道rtsp地址格式
  14. 压缩视图状态之ajax(atlas)修正版
  15. 解决mac突然连不上wifi了(wifi出现灰色小感叹号!)
  16. 中兴算法大赛深度学习模型优化加速解决方案总结
  17. 全球各国主要电商平台
  18. Linux中常见的指令(三):几个查看文件内容的指令,ctrl+c的理解
  19. python对淘宝运营有帮助吗_优秀的淘宝运营需要具备哪些能力
  20. 亲测绝对有用,,电脑不显示可连接WiFi列表,无法连接WiFi的解决办法。

热门文章

  1. SAP收购sysbase
  2. 如何在GraphPad Prism 9图表上添加图片或其他对象
  3. Meta分析如何进行敏感性分析
  4. Lidar SLAM | 地面三维激光雷达测试报告
  5. mac安装nvm及换源及node安装切换
  6. Qt学习(七):定时器QTimer
  7. 音频录入后以不同采样率输出
  8. php odbc连接sqlserver,php pdo连接sqlserver配置
  9. php psr2规范,php标准规范详解
  10. mysql 类型 自动转化_自动MySQL数据类型转换