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

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

动态代理:在程序运行时,运用反射机制动态创建而成。

动态代理三种方式

动态代理实现有三种方式,jdk动态代理(基于接口),cglib动态代理(基于继承),javassist(hibernate中使用这种方式)实现动态代理。

JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢?

这就需要CGLib了。

cglib如何实现代理

Cglib是一个优秀的动态代理框架,它的底层使用ASM在内存中动态的生成被代理类的子类,使用CGLIB即使代理类没有实现任何接口也可以实现动态代理功能。

CGLib原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。

cgLib动态代理实例

下面演示一个动态代理的实例。

导入maven 依赖

cglib 是基于asm 字节修改技术。导入 cglib 会间接导入 asm, ant, ant-launcher 三个jar 包。

<!-- cglib 动态代理依赖 begin -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version></dependency>
<!-- cglib 动态代理依赖 stop -->

CGLIB的核心类:

  • net.sf.cglib.proxy.Enhancer – 主要的增强类
  • net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现
  • net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用:
  • Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。

实现一个业务类,注意,这个业务类并没有实现任何接口:

public class HelloService {

    public HelloService() {
System.out.println("HelloService构造");
} public void sayHello() {
System.out.println("HelloService:sayHello");
}

net.sf.cglib.proxy.MethodInterceptor接口是最通用的回调(callback)类型,它经常被基于代理的AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法

public Object intercept(Object object, java.lang.reflect.Method method,

Object[] args, MethodProxy proxy) throws Throwable;

方法拦截器 实现 MethodInterceptor 接口:

public class HelloServiceInterceptor implements MethodInterceptor{

    /**
* sub:cglib生成的代理对象
* method:被代理对象方法
* objects:方法入参
* methodProxy: 代理方法
*/
@Override
public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("======插入前置通知======");
Object object = methodProxy.invokeSuper(sub, objects);
System.out.println("======插入后置通知======");
return object;
}

测试类,生成CGLIB代理对象调用目标方法:

public class CglibTest {
public static void main(String[] args) {
// 通过CGLIB动态代理获取代理对象的过程
Enhancer enhancer = new Enhancer();
// 设置enhancer对象的父类
enhancer.setSuperclass(HelloService.class);
// 设置enhancer的回调对象
enhancer.setCallback(new HelloServiceInterceptor());
// 创建代理对象
HelloService proxy= (HelloService)enhancer.create();
// 通过代理对象调用目标方法
proxy.sayHello();
}
}

Cglib 总结

  • CGlib可以传入接口也可以传入普通的类,接口使用实现的方式,普通类使用会使用继承的方式生成代理类.
  • 由于是继承方式,如果是 static方法,private方法,final方法等描述的方法是不能被代理的
  • 做了方法访问优化,使用建立方法索引的方式避免了传统JDK动态代理需要通过Method方法反射调用.
  • 提供callback 和filter设计,可以灵活地给不同的方法绑定不同的callback。编码更方便灵活。
  • CGLIB会默认代理Object中equals,toString,hashCode,clone等方法。比JDK代理多了clone。

性能优于JDK代理,CGLib如何实现动态代理的更多相关文章

  1. 死磕Spring之AOP篇 - 初识JDK、CGLIB两种动态代理

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

  2. 基于 CGLIB 库的动态代理机制

    之前的文章我们详细的介绍了 JDK 自身的 API 所提供的一种动态代理的实现,它的实现相对而言是简单的,但是却有一个非常致命性的缺陷,就是只能为接口中的方法完成代理,而委托类自己的方法或者父类中的方 ...

  3. 代理模式 & Java原生动态代理技术 & CGLib动态代理技术

    第一部分.代理模式  代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常 ...

  4. Cglib方法实现动态代理

    除了使用JDK方式产生动态代理外,Java还给我们提供了另外一种产生动态代理的方法,那就是使用cglib. cglib是这样实现动态代理的: · ①.针对类来实现代理 · ②对指定目标类产生一个子类 ...

  5. java提供类与cglib包实现动态代理

    终于有点空余时间,决定把之前学习的知识点整理一下,备以后复习. 动态代理有三角色:抽象角色,代理角色,真是角色. 第一个记录下java提供的动态代理.即使用Proxy类和InvocationHande ...

  6. CGLIB和Java动态代理的区别(笔记)

    java常用知识点: 1.Java动态代理只能够对接口进行代理,不能对普通的类进行代理(因为所有生成的代理类的父类为Proxy,Java类继承机制不允许多重继承):CGLIB能够代理普通类:2.Jav ...

  7. java--动态代理设计模式,CGLIB实现的动态代理设计模式

    代理设计模式 代理设计模式的基本形式 代理设计模式的核心思路,一个接口两个子类,一个子类完成核心业务操作,另一个完成与核心业务有关的辅助性操作.例如,编写一个简单的设计模式. package com. ...

  8. JDK动态代理(3)--------动态代理具体实现

    写个HelloWorld 接口 package com.spring.aop.proxy; public interface HelloWorld { public void sayHello(); ...

  9. java 代理模式二:动态代理

    java动态代理: java动态代理类位于java.lang.reflect包下,一般主要涉及两个类: 1.Interface InvocationHandler 该接口中仅定义了一个方法:Objec ...

随机推荐

  1. DOCKER学习_001:Docker简介

    一 Docker简介 1.1 docker由来 Docker的英文翻译是“码头工人”,即搬运工,它搬运的东西就是我们常说的集装箱Container,Container里面装的是任意类型的App.我们的 ...

  2. 【题解】SDOI2010所驼门王的宝藏(强连通分量+优化建图)

    [题解]SDOI2010所驼门王的宝藏(强连通分量+优化建图) 最开始我想写线段树优化建图的说,数据结构学傻了233 虽然矩阵很大,但是没什么用,真正有用的是那些关键点 考虑关键点的类型: 横走型 竖 ...

  3. Excel获取当前日期和时间

    在Excel中获取当前时间 1.第一种在空的单元格内输入函数“NOW()”回车即可获取当前时间如图 2.第二种选中空单元格“按住CTRL+:”回车即可获取当前时间 3.第一种在空的单元格内输入函数“t ...

  4. python集合的运算

    &  交集  | 并集    - 差集  ^ 异或集 # 在对集合做运算时,不会影响原来的集合,而是返回一个运算结果 # 创建两个集合 s = {1,2,3,4,5} s2 = {3,4,5, ...

  5. python循环语句(while和for)

    循环语句分成两种,while循环 和 for循环 作用:可以使指定的代码块重复指定的次数 while循环: # 语法: # while 条件表达式 : # 代码块 # else : # 代码块 # 执 ...

  6. APICloud开发者进阶之路 | UIPickerView 模块示例demo

    本文出自APICloud官方论坛 rongCloud2  3.2.8 版本更新后添加了发送小视频接口,发送文件接口. rongCloud2  概述 融云是国内首家专业的即时通讯云服务提供商,专注为互联 ...

  7. 来自PTA Basic Level的三只小野兽

    点我阅读原文 最近利用闲暇时间做了一下 PTA Basic Level[1] 里的题,里面现在一共有 95 道题,这些题大部分很基础,对于刷倦了 leetcode 的小伙伴可以去里面愉快的玩耍哦. 这 ...

  8. C# html生成图片保存下载

    最近有个需求,需要把内容生成图片,我找到一些资料可以将html页面生成图片并保存下载 下面是简单的实现 1.html页面 @{ Layout = null; } <!DOCTYPE html&g ...

  9. gradle 不用打开项目直接编译

    gradlew :api-client:install 编辑完后点击

  10. hive 动态分区

    非常重要的动态分区属性: hive.exec.dynamic.partition  是否启动动态分区.false(不开启) true(开启)默认是 false hive.exec.dynamic.pa ...