3、返回这个代理类实例,因为我们构造的代理类实现了 interfaces(也就是我们程序中传入的 fruitCakeMachine.getClass().getInterfaces() 里的所有接口,因此返回的代理类可以强转成 MachineCake 类型来调用接口中定义的方法。
CGLib动态代理的原理因为 JVM 并不允许在运行时修改原有类,所以所有的动态性都是通过新建类来实现的,上面说到的 Java 动态代理也不例外。所以对于 CGLib 动态代理的原理,其实也是通过动态生成代理类,最后由代理类来完成操作实现的。
对于 CGLib 动态代理的实现,我并没有深入到源码中,而是通过查阅资料了解了其大概的实现原理。
首先,我们在使用的时候通过 enhancer.setSuperclass(FruitCakeMachine.class) 传入了需要增加的类,CGLib 便会生成一个继承了改类的代理类。
接着,我们通过 enhancer.setCallback(new ApricotInterceptor()) 传入了代理类对象,CGLib 通过组装两个类的结构实现一个静态代理,从而达到具体的目的。
而在 CGLib 生成新类的过程中,其使用的是一个名为 ASM 的东西,它对 Java 的 class 文件进行操作、生成新的 class 文件。如果你对 CGLib 的原理感兴趣,不妨看看这篇文章:从兄弟到父子:动态代理在民间是怎么玩的?
动态代理的应用动态代理在代码界可是有非常重要的意义,我们开发用到的许多框架都使用到了这个概念。我所知道的就有:Spring AOP、Hibernate、Struts 使用到了动态代理。
Spring AOP。Spring 最重要的一个特性是 AOP(Aspect Oriented Programming 面向切面编程),利用 Spring AOP 可以快速地实现权限校验、安全校验等公用操作。而 Spring AOP 的原理则是通过动态代理实现的,默认情况下 Spring AOP 会采用 Java 动态代理实现,而当该类没有对应接口时才会使用 CGLib 动态代理实现。
Hibernate。Hibernate 是一个常用的 ORM 层框架,在获取数据时常用的操作有:get() 和 load() 方法,它们的区别是:get() 方法会直接获取数据,而 load() 方法则会延迟加载,等到用户真的去取数据的时候才利用代理类去读数据库。
Struts。Struts 现在虽然因为其太多 bug 已经被抛弃,但是曾经用过 Struts 的人都知道 Struts 中的拦截器。拦截器有非常强的 AOP 特性,仔细了解之后你会发现 Struts 拦截器其实也是用动态代理实现的。
总结我们通过蛋糕店的不同业务场景介绍了静态代理和动态代理的应用,接着重点介绍了动态代理两种实现方式(Java 动态代理、CGLib 动态代理)的使用方法及其实现原理,其中还针对 Java 动态代理的源码进行了简单的分析。最后,我们介绍了动态代理在实际上编程中的应用(Spring AOP、Hibernate、Struts)。
希望这篇文章帮助大家更好地理解动态代理。
以上。
文章首发于【博客园-陈树义】,点击跳转到原文深入浅出Java动态代理