【Java入门提高篇】Day12 Java代理——Cglib动态代理

简介:   今天来介绍另一种更为强大的代理——Cglib动态代理。  什么是Cglib动态代理?  我们先回顾一下上一篇的jdk动态代理,jdk动态代理是通过接口来在运行时动态创建委托类的代理对象,但是跟静态代理一样有一个缺点,就是必须和委托类实现相同的接口,当接口数量增加时,便需要增加代理类的数量才能满足需求,而且如果委托类是别人写的,而且没有实现任何接口,那么jdk动态代理就有些力不从心了。

  今天来介绍另一种更为强大的代理——Cglib动态代理。

  什么是Cglib动态代理?

  我们先回顾一下上一篇的jdk动态代理,jdk动态代理是通过接口来在运行时动态创建委托类的代理对象,但是跟静态代理一样有一个缺点,就是必须和委托类实现相同的接口,当接口数量增加时,便需要增加代理类的数量才能满足需求,而且如果委托类是别人写的,而且没有实现任何接口,那么jdk动态代理就有些力不从心了。

  这时候Cglib动态代理就脱颖而出了,Cglib并不依赖接口,可以直接生成委托类的代理对象,而且可以代理委托类的任意非final修饰的public和protected方法,我们可以先来看一个栗子。

  先定义一个Programmer类:

public class Programmer {

    private String name;
    
    public void setName(String name) {
     System.out.println("Setting Name.");
this.name = name; }public void code(){ System.out.println(name + " is writing bugs."); } }

  然后定义一个代理类:

public class ProgrammerProxy implements MethodInterceptor {

    /**
     * 内部持有委托类对象的引用
     */
    private Object target;

    /**
     * 创建代理类对象
     */
    public Programmer createProxy(Programmer object){
        target = object;
        //创建Enhancer对象
        Enhancer enhancer = new Enhancer();
        //设置要代理的目标类,以扩展功能
        enhancer.setSuperclass(this.target.getClass());
        //设置单一回调对象,在回调中拦截对目标方法的调用
        enhancer.setCallback(this);
        //设置类加载器
        enhancer.setClassLoader(object.getClass().getClassLoader());
        //创建代理对象
        return (Programmer)enhancer.create();
    }

    /**
     * 回调方法:在代理实例上拦截并处理目标方法的调用,返回结果
     * @param proxy  代理类
     * @param method 被代理的方法
     * @param params 该方法的参数数组
     * @param methodProxy
     */
    @Override
    public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
        //调用之前处理
        doBefore();

        //调用原方法
        method.invoke(target,params);

        //调用之后处理
        doAfter();

        return null;
    }

    private void doAfter() {
        System.out.println("do after.");
    }

    private void doBefore() {
        System.out.println("do before.");
    }

}

  然后测试一下:

public class ProxyTest {

    @Test
    public void testCglibProxy(){
        //创建一个Programmer对象
        Programmer programmerA = new Programmer();
        programmerA.setName("Frank");

        //创建代理对象
        Programmer programmerProxyA = new ProgrammerProxy().createProxy(programmerA);
        programmerProxyA.code();

        //修改代理对象
        programmerProxyA.setName("Wang");
        programmerProxyA.code();

        //修改委托类对象
        programmerA.setName("Song");
        programmerProxyA.code();
    }
}

  输出如下:

Setting Name.
do before.
Frank is writing bugs.
do after.
do before.
Setting Name.
do after.
do before.
Wang is writing bugs.
do after.
Setting Name.
do before.
Song is writing bugs.
do after.

  Cglib实现动态代理的步骤也不是很麻烦,先创建一个类实现MethodInterceptor接口,重写intercept方法,在intercep中可以截获委托类的所有非final修饰的public和protected方法,上例中,method.invoke(target,params);即为调用原对象的原方法,在代理类中保存了委托类对象的引用,这一点跟JDK动态代理是一样的。在调用原方法前先调用了doBefore方法,调用之后还调用了doAfter方法,从而实现了代理功能。至于createProxy方法,也只是一个固定步骤,先创建Enhance对象,然后将委托类的一些属性往里塞,然后调用create方法来动态生成代理对象。

  在测试类中,为了更明显的说明代理类与委托类的关系,分别用代理类对象programmerProxyA和委托类对象programmerA对name字段进行修改,可以产生一样的效果。

  下面来对比一下Cglib动态代理与JDK动态代理:

  1.两者都是动态代理,都是运行时动态生成代理对象。

  2.JDK动态代理利用的是接口信息来实现的代理,委托类必须实现某个或者某些接口,而Cglib则是利用继承关系,利用asm在运行时动态生成委托类的子类,从而实现对委托类的代理。因此不依赖接口。

  3.Cglib由于是利用继承关系来实现代理的,因此无法代理被final修饰的类以及被final修饰的方法。

  4.Cglib一般来说效率要比JDK动态代理效率更高,可以实现的代理也更为强大。

  当然,具体情况具体分析,虽然Cglib比Jdk动态代理更强大,但并不一定各个地方都强行使用,有时候JDK动态代理相对来说更加简单粗暴。

  至此,本篇完结,代理相关内容讲解完毕,欢迎大家继续关注。

  jar包下载地址:http://download.csdn.net/download/qiuyingjia/10181844

真正重要的东西,用眼睛是看不见的。
相关文章
|
1月前
|
XML Java 数据库连接
谈谈Java反射:从入门到实践,再到原理
谈谈Java反射:从入门到实践,再到原理
58 0
|
20天前
|
关系型数据库 Java 开发工具
Java入门高频考查基础知识9(15问万字参考答案)
本文探讨了Spring Cloud的工作原理,包括注册中心的心跳机制、服务发现机制,以及Eureka默认的负载均衡策略。同时,概述了Spring Boot中常用的注解及其实现方式,并深入讨论了Spring事务的注解、回滚条件、传播性和隔离级别。文章还介绍了MySQL的存储引擎及其区别,特别关注了InnoDB如何实现MySQL的事务处理。此外,本文还详细探讨了MySQL索引,包括B+树的原理和设计索引的方法。最后,比较了Git和SVN的区别,并介绍了Git命令的底层原理及流程。
29 0
Java入门高频考查基础知识9(15问万字参考答案)
|
20天前
|
存储 缓存 算法
Java入门高频考查基础知识4(字节跳动面试题18题2.5万字参考答案)
最重要的是保持自信和冷静。提前准备,并对自己的知识和经验有自信,这样您就能在面试中展现出最佳的表现。祝您面试顺利!Java 是一种广泛使用的面向对象编程语言,在软件开发领域有着重要的地位。Java 提供了丰富的库和强大的特性,适用于多种应用场景,包括企业应用、移动应用、嵌入式系统等。下是几个面试技巧:复习核心概念、熟悉常见问题、编码实践、项目经验准备、注意优缺点、积极参与互动、准备好问题问对方和知其所以然等,多准备最好轻松能举一反三。
46 0
Java入门高频考查基础知识4(字节跳动面试题18题2.5万字参考答案)
|
20天前
|
存储 算法 JavaScript
Java入门高频考查算法逻辑基础知识3-编程篇(超详细18题1.8万字参考编程实现)
解决这类问题时,建议采取下面的步骤: 理解数学原理:确保你懂得基本的数学公式和法则,这对于制定解决方案至关重要。 优化算法:了解时间复杂度和空间复杂度,并寻找优化的机会。特别注意避免不必要的重复计算。 代码实践:多编写实践代码,并确保你的代码是高效、清晰且稳健的。 错误检查和测试:要为你的代码编写测试案例,测试标准的、边缘情况以及异常输入。 进行复杂问题简化:面对复杂的问题时,先尝试简化问题,然后逐步分析和解决。 沟通和解释:在编写代码的时候清晰地沟通你的思路,不仅要写出正确的代码,还要能向面试官解释你的
32 0
|
20天前
|
存储 Java 编译器
Java入门高频考查基础知识2(超详细28题2.5万字答案)
多态是面向对象编程中的一个重要概念,它允许不同类的对象对同一消息作出不同的响应。在具体实现上,多态允许一个父类的引用指向其子类的对象,并根据实际指向的对象的类型来调用相应的方法。在 Java 中,多态可以通过以下几种方式实现:在同一个类中,方法名相同,但形参列表不同,实现了多态。子类可以重写(覆盖)其父类的方法,实现多态。在父类引用中调用该方法时,根据实际指向的子类对象的类型来调用相应的方法实现。
38 0
|
1月前
|
算法 Java
Java必刷入门递归题×5(内附详细递归解析图)
Java必刷入门递归题×5(内附详细递归解析图)
21 1
|
1月前
|
Java
Java入门必刷的基础题1(八道)
Java入门必刷的基础题1(八道)
20 0
|
1月前
|
分布式计算 Oracle Java
第一篇CSDN博客——Java入门指南:学习Java编程的第一步
第一篇CSDN博客——Java入门指南:学习Java编程的第一步
|
1月前
|
Java API 开发者
Java代理模式——静态代理与动态代理
Java代理模式——静态代理与动态代理
26 1
|
Java 数据库连接
Java之jdk和CGLib实现动态代理
Java之jdk和CGLib实现动态代理
110 0