Java的动态代理模式之Cglib代理详解

 更新时间:2023年11月28日 08:33:59   作者:四叶草  
这篇文章主要介绍了Java的动态代理模式之Cglib代理详解,Cglib代理也叫作 子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能扩展, 有些书也将Cglib代理归属到动态代理,需要的朋友可以参考下

1.Cglib 代理模式的基本介绍

  1. 静态代理和 JDK 代理模式都要求目标对象是实现一个接口,但是有时候目标对象只是一个 单独的对象,并没 有实现任何的接口,这个时候可使用目标对象子类来实现代理-这就是 Cglib 代理
  2. Cglib代理也叫作 子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能扩展, 有些书也将Cglib代理归属到动态代理。
  3. Cglib 是一个强大的高性能的代码生成包,它可以在运行期扩展 java 类与实现 java 接口.它广泛的被许多 AOP 的框架使用,例如 SpringAOP,实现方法拦截
  4. 在 AOP 编程中如何选择代理模式:

目标对象需要实现接口,用 JDK 代理

目标对象不需要实现接口,用 Cglib 代理

Cglib 包的底层是通过使用字节码处理框架 ASM 来转换字节码并生成新的类

2.Cglib 代理模式实现步骤

需要引入 cglib 的 jar 文件

/*
cglib包结构:
net.sf.cglib.core    	底层字节码处理类。
net.sf.cglib.transform  该包中的类用于class文件运行时转换或编译时转换。
net.sf.cglib.proxy    	该包中的类用于创建代理和方法拦截。
net.sf.cglib.reflect    该包中的类用于快速反射,并提供了C#风格的委托。
net.sf.cglib.util    	集合排序工具类。
net.sf.cglib.beans    	JavaBean工具类。
*/

在内存中动态构建子类,注意代理的类不能为 final,否则报错java.lang.IllegalArgumentException:

目标对象的方法如果为 final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.

3.cglib动态代理相关的基础类

net.sf.cglib.proxy.Enhancer 主要的增强类。

net.sf.cglib.proxy.MethodInterceptor 主要的方法拦截类,它是Callback接口的子接口,需要用户实现。

net.sf.cglib.proxy.MethodProxy JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用。

cglib是通过动态的生成一个子类去覆盖所要代理类的非final方法,并设置好callback,则原有类的每个方法调用就会转变成调用用户定义的拦截方法(intercept)

4.Cglib 代理模式应用实例

4.1 导入pom.xml依赖

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.1</version>
</dependency>

4.2 目标类

//火车站
public class TrainStation {

    public void sell() {
        System.out.println("火车站卖票");
    }
}

4.3 代理工厂

//代理工厂
public class ProxyFactory implements MethodInterceptor {

    //声明目标对象
    private TrainStation target = new TrainStation();

    public TrainStation getProxyObject() {
        //创建Enhancer对象,类似于JDK动态代理的Proxy类,下一步就是设置几个参数
        Enhancer enhancer =new Enhancer();

        //设置代理对象的父类的字节码对象(Class类型的对象) , 指定代理对象的父类
        enhancer.setSuperclass(target.getClass());

        //设置回调函数 , 实现调用代理对象的方法时最终都会执行MethodInterceptor的子实现类的intercept方法 , 在这个函数中利用反射完成任意目标类方法的调用
        enhancer.setCallback(this);

        //设置完参数后就可以 ,默认返回的是Object类型 , 可以进行强转 , 创建真正的代理对象
        TrainStation obj = (TrainStation) enhancer.create();
        return obj;
    }
    // intercept方法参数说明:
    //		返回值类型是调用方法的返回值类型
	//		o : 代理对象
	//		method : 真实对象中的方法的Method实例对象
	//		args : 实际参数 , 可以是0到N个
	//		methodProxy :代理对象中的方法的method实例

    public TrainStation intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理点收取一些服务费用(CGLIB动态代理方式)");
        //调用目标对象的方法
        TrainStation result = (TrainStation) methodProxy.invokeSuper(o, args);
        return result;
    }
}

Enhancer类的常用方法

方法名功能
public Enhancer() , 无参构造创建Enhancer对象,类似于JDK动态代理的Proxy类,并不是真正的代理对象 , 还没有设置参数
setSuperclass()设置代理对象的父类的字节码对象(Class类型的对象) , 指定代理对象的父类 , 参数一般写目标类的Class对象
setCallback()设置执行哪个对象的回调函数 , 调用代理对象的方法时最终都会执行MethodInterceptor接口的子实现类对象的intercept方法 , 在intercept方法中利用反射完成任意目标类方法的调用 一般让代理工厂实现MethodInterceptor接口 , 那么方法参数就可以写this,这时MethodInterceptor接口的子实现类对象就是代理工厂对象
public Object create()创建真正的代理对象 , 默认返回的是Object类型 , 可以强转为目标对象类型 , 创建真正的代理对象

4.4 测试类

//测试类
public class Client {
    public static void main(String[] args) {
        //创建代理工厂对象
        ProxyFactory factory = new ProxyFactory();
        
        //获取代理对象
        TrainStation proxyObject = factory.getProxyObject();

        proxyObject.sell();
    }
}

5 jdk代理和CGLIB代理

  • 使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,在JDK1.6之前比使用Java反射效率要高。
  • 唯一需要注意的是,CGLib不能对声明为final的类或者方法进行代理,因为CGLib原理是动态生成被代理类的子类。final修饰类不能被继承 , final修饰的方法不能被重写
  • 在JDK1.6、JDK1.7、JDK1.8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLib代理效率,只有当进行大量调用的时候,JDK1.6和JDK1.7比CGLib代理效率低一点,但是到JDK1.8的时候,JDK代理效率高于CGLib代理。所以如果有接口使用JDK动态代理,如果没有接口使用CGLIB代理。

6 代理模式优缺点及使用场景

优点:

  • 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
  • 代理对象可以扩展目标对象的功能;
  • 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度;

缺点:

  • 增加了系统的复杂度;

使用场景:

  • 远程(Remote)代理
    • 本地服务通过网络请求远程服务。为了实现本地到远程的通信,我们需要实现网络通信,处理其中可能的异常。为良好的代码设计和可维护性,我们将网络通信部分隐藏起来,只暴露给本地服务一个接口,通过该接口即可访问远程服务提供的功能,而不必过多关心通信部分的细节。RPC思想
  • 防火墙(Firewall)代理
    • 当你将浏览器配置成使用代理功能时,防火墙就将你的浏览器的请求转给互联网;当互联网返回响应时,代理服务器再把它转给你的浏览器。
  • 保护(Protect or Access)代理
    • 务一个接口,通过该接口即可访问远程服务提供的功能,而不必过多关心通信部分的细节。RPC思想
  • 防火墙(Firewall)代理
    • 当你将浏览器配置成使用代理功能时,防火墙就将你的浏览器的请求转给互联网;当互联网返回响应时,代理服务器再把它转给你的浏览器。
  • 保护(Protect or Access)代理
    • 控制对一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限。

到此这篇关于Java的动态代理模式之Cglib代理详解的文章就介绍到这了,更多相关Cglib代理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringMVC访问静态资源的方法

    SpringMVC访问静态资源的方法

    本篇文章主要介绍了SpringMVC访问静态资源的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • java读取枚举类的值转成list和map方式

    java读取枚举类的值转成list和map方式

    这篇文章主要介绍了java读取枚举类的值转成list和map方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • Spring Boot 数据校验@Valid+统一异常处理的实现

    Spring Boot 数据校验@Valid+统一异常处理的实现

    这篇文章主要介绍了Spring Boot 数据校验@Valid+统一异常处理的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-04-04
  • Java实现简易计算器(逆波兰表达式)

    Java实现简易计算器(逆波兰表达式)

    这篇文章主要为大家详细介绍了Java实现简易计算器,逆波兰表达式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-07-07
  • 详解在Spring MVC中使用注解的方式校验RequestParams

    详解在Spring MVC中使用注解的方式校验RequestParams

    本篇文章主要介绍了详解在Spring MVC中使用注解的方式校验RequestParams ,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-03-03
  • Spring boot中自定义Json参数解析器的方法

    Spring boot中自定义Json参数解析器的方法

    这篇文章主要介绍了Spring boot中自定义Json参数解析器的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01
  • Java使用Thread创建多线程并启动操作示例

    Java使用Thread创建多线程并启动操作示例

    这篇文章主要介绍了Java使用Thread创建多线程并启动操作,结合实例形式分析了Java基于Thread类的多线程定义与启动简单操作技巧,需要的朋友可以参考下
    2018-06-06
  • JAVA多线程编程实例详解

    JAVA多线程编程实例详解

    这篇文章主要介绍了JAVA多线程编程,结合实例形式总结分析了多线程、锁、线程池等相关原理及使用技巧,需要的朋友可以参考下
    2019-09-09
  • 完美解决MybatisPlus插件分页查询不起作用总是查询全部数据问题

    完美解决MybatisPlus插件分页查询不起作用总是查询全部数据问题

    这篇文章主要介绍了解决MybatisPlus插件分页查询不起作用总是查询全部数据问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • Java JWT实现跨域身份验证方法详解

    Java JWT实现跨域身份验证方法详解

    JWT(JSON Web Token)是目前流行的跨域认证解决方案,是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。本文将介绍JWT如何实现跨域身份验证,感兴趣的可以学习一下
    2022-01-01

最新评论