原文地址:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html

高亮部分是我的理解。

JAVA的动态代理

代理模式

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

按照代理的创建时期,代理类可以分为两种。

  • 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
  • 动态代理:在程序运行时,运用反射机制动态创建而成。

首先看一下静态代理:

  1. 1、Count.java
  2. package net.battier.dao;
  3.  
  4. /**
  5.  * 定义一个账户接口
  6.  *
  7.  * @author Administrator
  8.  *
  9.  */
  10. public interface Count {
  11.     // 查看账户方法
  12.     public void queryCount();
  13.  
  14.     // 修改账户方法
  15.     public void updateCount();
  16.  
  17. }
  18.  
  19. 2、CountImpl.java
  20. package net.battier.dao.impl;
  21.  
  22. import net.battier.dao.Count;
  23.  
  24. /**
  25.  * 委托类(包含业务逻辑)
  26.  *
  27.  * @author Administrator
  28.  *
  29.  */
  30. public class CountImpl implements Count {
  31.  
  32.     @Override
  33.     public void queryCount() {
  34.         System.out.println("查看账户方法...");
  35.  
  36.     }
  37.  
  38.     @Override
  39.     public void updateCount() {
  40.         System.out.println("修改账户方法...");
  41.  
  42.     }
  43.  
  44. }
  45.  
  46. CountProxy.java
  47. package net.battier.dao.impl;
  48.  
  49. import net.battier.dao.Count;
  50.  
  51. /**
  52.  * 这是一个代理类(增强CountImpl实现类)
  53.  *
  54.  * @author Administrator
  55.  *
  56.  */
  57. public class CountProxy implements Count {
  58.     private CountImpl countImpl;
  59.  
  60.     /**
  61.      * 覆盖默认构造器
  62.      *
  63.      * @param countImpl
  64.      */
  65.     public CountProxy(CountImpl countImpl) {
  66.         this.countImpl = countImpl;
  67.     }
  68.  
  69.     @Override
  70.     public void queryCount() {
  71.         System.out.println("事务处理之前");
  72.         // 调用委托类的方法;
  73.         countImpl.queryCount();
  74.         System.out.println("事务处理之后");
  75.     }
  76.  
  77.     @Override
  78.     public void updateCount() {
  79.         System.out.println("事务处理之前");
  80.         // 调用委托类的方法;
  81.         countImpl.updateCount();
  82.         System.out.println("事务处理之后");
  83.  
  84.     }
  85.  
  86. }
  87.  
  88. 3、TestCount.java
  89. package net.battier.test;
  90.  
  91. import net.battier.dao.impl.CountImpl;
  92. import net.battier.dao.impl.CountProxy;
  93.  
  94. /**
  95.  *测试Count类
  96.  *
  97.  * @author Administrator
  98.  *
  99.  */
  100. public class TestCount {
  101.     public static void main(String[] args) {
  102.         CountImpl countImpl = new CountImpl();
  103.         CountProxy countProxy = new CountProxy(countImpl);
  104.         countProxy.updateCount();
  105.         countProxy.queryCount();
  106.  
  107.     }
  108. }

观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。

静态代理就是设计模式中讲的代理模式。

再来看一下动态代理:

JDK动态代理中包含一个类和一个接口: 
InvocationHandler接口: 
public interface InvocationHandler { 
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 

参数说明: 
Object proxy:指被代理的对象。 
Method method:要调用的方法 
Object[] args:方法调用时所需要的参数

可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。

InvocationHandler可以理解成就是上面静态代理中继承了被代理类的代理类。它覆盖(代理)了被代理类的方法。

Proxy类: 
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法: 
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 
InvocationHandler h) 
                               throws IllegalArgumentException 
参数说明: 
ClassLoader loader:类加载器 
Class<?>[] interfaces:得到全部的接口 
InvocationHandler h:得到InvocationHandler接口的子类实例

Proxy可以理解成一个工具类,它的目的是传入一个接口,动态生成这个接口的实现类,当然在生成的过程中,如果系统里已经有了一个实现了这个接口的类,那么就对这个实现类进行代理了。

动态代理 
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。

动态代理示例:

  1.  1、BookFacade.java
  2. package net.battier.dao;
  3.  
  4. public interface BookFacade {
  5.     public void addBook();
  6. }
  7.  
  8. 2、BookFacadeImpl.java
  9. package net.battier.dao.impl;
  10.  
  11. import net.battier.dao.BookFacade;
  12.  
  13. public class BookFacadeImpl implements BookFacade {
  14.  
  15.     @Override
  16.     public void addBook() {
  17.         System.out.println("增加图书方法。。。");
  18.     }
  19.  
  20. }
  21.  
  22. 、BookFacadeProxy.java
  23.  
  24. package net.battier.proxy;
  25.  
  26. import java.lang.reflect.InvocationHandler;
  27. import java.lang.reflect.Method;
  28. import java.lang.reflect.Proxy;
  29.  
  30. /**
  31.  * JDK动态代理代理类
  32.  *
  33.  * @author student
  34.  *
  35.  */
  36. public class BookFacadeProxy implements InvocationHandler {
  37.     private Object target;
  38.     /**
  39.      * 绑定委托对象并返回一个代理类
  40.      * @param target
  41.      * @return
  42.      */
  43.     public Object bind(Object target) {
  44.         this.target = target;
  45.         //取得代理对象
  46.         return Proxy.newProxyInstance(target.getClass().getClassLoader(),
  47.                 target.getClass().getInterfaces(), this); //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)
  48.     }
  49.  
  50.     @Override
  51.     /**
  52.      * 调用方法
  53.      */
  54.     public Object invoke(Object proxy, Method method, Object[] args)
  55.             throws Throwable {
  56.         Object result=null;
  57.         System.out.println("事物开始");
  58.         //执行方法
  59.         result=method.invoke(target, args);
  60.         System.out.println("事物结束");
  61.         return result;
  62.     }
  63.  
  64. }
  65.  
  66. 3、TestProxy.java
  67. package net.battier.test;
  68.  
  69. import net.battier.dao.BookFacade;
  70. import net.battier.dao.impl.BookFacadeImpl;
  71. import net.battier.proxy.BookFacadeProxy;
  72.  
  73. public class TestProxy {
  74.  
  75.     public static void main(String[] args) {
  76.         BookFacadeProxy proxy = new BookFacadeProxy();
  77.         BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());
  78.         bookProxy.addBook();
  79.     }
  80.  
  81. }

但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。

Cglib动态代理 
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 
示例

  1. 1、BookFacadeCglib.java
  2. package net.battier.dao;
  3.  
  4. public interface BookFacade {
  5.     public void addBook();
  6. }
  7.  
  8. 2、BookCadeImpl1.java
  9. package net.battier.dao.impl;
  10.  
  11. /**
  12.  * 这个是没有实现接口的实现类
  13.  *
  14.  * @author student
  15.  *
  16.  */
  17. public class BookFacadeImpl1 {
  18.     public void addBook() {
  19.         System.out.println("增加图书的普通方法...");
  20.     }
  21. }
  22.  
  23. 3、BookFacadeProxy.java
  24. package net.battier.proxy;
  25.  
  26. import java.lang.reflect.Method;
  27.  
  28. import net.sf.cglib.proxy.Enhancer;
  29. import net.sf.cglib.proxy.MethodInterceptor;
  30. import net.sf.cglib.proxy.MethodProxy;
  31.  
  32. /**
  33.  * 使用cglib动态代理
  34.  *
  35.  * @author student
  36.  *
  37.  */
  38. public class BookFacadeCglib implements MethodInterceptor {
  39.     private Object target;
  40.  
  41.     /**
  42.      * 创建代理对象
  43.      *
  44.      * @param target
  45.      * @return
  46.      */
  47.     public Object getInstance(Object target) {
  48.         this.target = target;
  49.         Enhancer enhancer = new Enhancer();
  50.         enhancer.setSuperclass(this.target.getClass());
  51.         // 回调方法
  52.         enhancer.setCallback(this);
  53.         // 创建代理对象
  54.         return enhancer.create();
  55.     }
  56.  
  57.     @Override
  58.     // 回调方法
  59.     public Object intercept(Object obj, Method method, Object[] args,
  60.             MethodProxy proxy) throws Throwable {
  61.         System.out.println("事物开始");
  62.         proxy.invokeSuper(obj, args);
  63.         System.out.println("事物结束");
  64.         return null;
  65.  
  66.  
  67.     }
  68.  
  69. }
  70.  
  71. 4、TestCglib.java
  72. package net.battier.test;
  73.  
  74. import net.battier.dao.impl.BookFacadeImpl1;
  75. import net.battier.proxy.BookFacadeCglib;
  76.  
  77. public class TestCglib {
  78.  
  79.     public static void main(String[] args) {
  80.         BookFacadeCglib cglib=new BookFacadeCglib();
  81.         BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());
  82.         bookCglib.addBook();
  83.     }
  84. }

来自网络:

CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。除了CGLIB包,脚本语言例如Groovy和BeanShell,也是使用ASM来生成java的字节码。当然不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

ASM是一个java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。

mybatis也是通过JDK的动态代理来实现动态生成dao接口的实现类的。

我理解大概的思路应该:

  • 根据配置的包路径,扫描下面的接口。
  • 为每个接口生成代理类。
  • 将代理类注册为spring的bean。
  • 在spring调用bean的时候,代理类接管了方法的调用。
  • 代理类根据配置文件中的sql,执行方法的调用。

java动态代理(JDK和cglib)(转载)的更多相关文章

  1. 动态代理jdk和cglib的区别

    学习来源贴:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类, ...

  2. 动态代理(JDK、CGLIB)

    JDK-Proxy(动态代理): 特点:要求被代理的对象必须接口 缺点:如果一个对象没有任何接口实现,则不能使用JDK动态代理 1.创建一个Animal 提供一个方法 2.创建一个cat类.实现Ain ...

  3. Java动态代理-JDK自带实现

    上篇文章讲解了什么是静态代理,但是静态代理有一个问题就是需要建立很多的代理类,这样我们需要修改代理的方法的时候,需要在每个类中都要修改,这对于我们来说:当代理类很多的时候工作量就会成倍的增加. 于是针 ...

  4. Java动态代理 ----- jdk代理与cglib代理

    1.jdk代理 针对接口进行代理,接口可以没有方法, InvocationHandler会拦截所有方法,不过好像意义不大....只能执行Object类的方法,执行结果有点奇怪... package t ...

  5. 《转》JAVA动态代理(JDK和CGLIB)

    该文章转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的 ...

  6. 《转》java动态代理(JDK和cglib)

    该文章转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的 ...

  7. [转]java动态代理(JDK和cglib)

    转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html java动态代理(JDK和cglib) JAVA的动态代理 代理模式 代理 ...

  8. java动态代理(JDK和cglib)

    转:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代 ...

  9. java动态代理(JDK和cglib实现对比)

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt214 JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特 ...

随机推荐

  1. 解决ssh链接慢问题

    1,ssh -v root@ip 2,查看哪里卡住了 一般情况就是卡在debug1: SSH2_MSG_SERVICE_ACCEPT received 3,如果是上面卡住了 修改/etc/ssh/ss ...

  2. flutter image_picker

    点击选中图片,底部弹窗让用户选择使用相册还是相机,用户选中选项后,跳转到对应的相册或者相机功能,结果将图片显示出来 image_picker: ^0.6.1+4 iOS使用image_picker需要 ...

  3. 基于 Linux Bridge 的 Neutron 多平面网络实现原理

    目录 文章目录 目录 前言 前文列表 多平面网络 Local(本地网络) Flat(扁平网络) 配置 Flat 网络 VLAN 配置 VLAN 网络 VxLAN 配置 VxLAN 网络 GRE 前言 ...

  4. LoadRunner 技巧之 自动关联

    LoadRunner 技巧之 自动关联 这一节讲loadunner 关联的问题,其实这个东西理解起来简单,但说起来比较麻烦. 关联的原理:                               ...

  5. Java学习之==>面向对象编程 Part2

    一.封装 封装,即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别:将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结 ...

  6. CentOS 7.x关闭/开启防火墙出现Unit iptables.service failed to load: No such file or directory问题解决

    一直用CentOS 6.x,今天用CentOS7.3版本时,防火墙配置后执行service iptables start出现”Failed to restart iptables.service: U ...

  7. Day05:循环问题 / 数组

    循环嵌套 循环结构中包含完整的循环结构. 注意: 循环嵌套不限层次 各种循环语句都可以互相嵌套 内层循环中出现的break和continue只作用在内层循环中 外层循环循环一次 内层循环循环一遍 Ja ...

  8. tarjan缩点相关知识及代码

    emmm原谅我确实是找不到不用缩点的tarjan题才会想到自学一下缩点这个东西的.. 题目没有,只能自己出数据并手动模拟... 首先看一张图(懒得画,还是看输入数据吧,劳烦自行画图..) 7 9(n个 ...

  9. Ubuntu环境配置机器安装驱动

    ubuntu_environment_config.md thead > tr > th { text-align: left; border-bottom: 1px solid; } t ...

  10. AGC037 C Numbers on a Circle【思维】

    题目传送门 题意 这道题被某大佬改编拿来出成考试题,是长这个样子的: 好的,其实这才是真正的题意: 给定初始序列和最终序列,每次选择一个数变成自己和相邻2个数的和.问初始序列是否可以变为最终序列,若可 ...