资讯专栏INFORMATION COLUMN

Java中的动态代理

CastlePeaK / 1342人阅读

摘要:要明白,动态代理类的存在意义是为了拦截方法并修改逻辑而动态代理的局限性之一就是只能拦截接口所声明的方法。因为动态代理类是继承自业务类,所以该类和方法不能声明成无法继承或重写。者最终都是生成了一个新的动态代理类对象。

动态代理 1、先谈静态代理

对于静态代理,我们已经很熟悉了。我们拥有一个抽象类,真实类继承自抽象类并重写其业务方法,代理类持有真实类的对象实例,在重写业务方法中通过调用真实类的方法,并且添加自己的逻辑。这样代理类就实现了对真实类的行为代理。

静态代理的缺点在于,我们需要实现多个代理类,这无疑是很崩溃的。

2、JDK动态代理
优点先行:我们说静态代理的缺点在于需要为每一个真实类都生成一个对应的代理类,这样就很繁琐。动态代理呢,我们是动态生成目标类的动态代理类,根本不需要为每一个只需要定义一个动态代理类,就可以代理所有、无数的真实类;当然我们需要一个类来实现InvocationHandler接口即可。也就是说我们只需要一个类即可。

java中提供了一个接口InvocationHandlerProxy类来实现动态代理。

InvocationHandler接口是代理实例用来调用处理程序(代理行为)的接口,它只有一个方法。接收的参数为:动态代理对象,代理对象调用的接口方法的实例,执行参数。

就如下面的Market类实现了InvocationHandler接口,内部的Object target用来持有动态代理的真实对象实例,bind方法用来接收外部真实类对象传递给target。然后重点就是重写invoke方法了,这个方法和下面的Proxy类一起讲解。

这个类是用来处理动态代理的逻辑的,它的作用是接收生成的动态代理对象和被代理对象实现的接口与运行时的参数,这样就能拦截对接口方法的调用,从而实现自己的拦截逻辑。

如下图,我们在测试类中,使用Proxy类的newProxyInstance静态方法来生成动态代理对象。该方法很重要,传入的参数:被代理类的类加载器,被代理类的所实现的接口(用数组保存的),实现了InvocationHandler的接口的动态代理处理类。

这个类用来生成了动态代理的对象,很神奇的是,我们调用接口的方法时,就发现方法被拦截了,这时候生成的是动态代理对象,所以接口方法的逻辑已经是被拦截的逻辑了。(这里我们看成是一个新的动态代理的对象就好了)

为避免混乱,将包、类的结构给出:

动态代理类的命名规则:包名+$Proxy+id,同一个接口的实现类的id是相同的。

JDK动态代理的总结(不足)

1.JDK动态代理是通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法。因此,对一个类而言,如果想要对它使用JDK动态代理,那么这个类就必须实现接口interface,并且我们拦截的是其接口声明的方法才行。简言之,JDK动态代理只能对实现了接口的类生成代理,而不能针对未实现接口的类

2.我们发现,在JDK动态代理的实现过程中,我们无法对接口中的各个方法都实现一段独有的逻辑(如果被代理类实现的接口有多个方法,我们的动态代理的拦截逻辑却只有一段,所有的方法被拦截时都是用相同的逻辑来处理)。这是一个很大的问题。

3.JDK动态代理生成的动态代理类,是无法调用原业务类自己拥有的方法的(即接口中没有声明的方法)。要明白,动态代理类的存在意义是为了拦截方法并修改逻辑;而JDK动态代理的局限性之一就是只能拦截接口所声明的方法。

4.JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

3、CGLib动态代理

和JDK动态代理不同的是,CGLib动态代理解决了JDK动态代理的第一个不足。也就是说,如果一个类没有实现接口,那么我们还可以使用CGLib来生成其动态代理对象。

这里我们要讲到MethodInterceptor接口了。注意,CGLib动态代理并不是JDK中的类,它是外部的lib包。

我们还需要结合动态代理对象的生成来讲解。

同样,我们只需要定义一个动态代理的处理类即可。实现了MethodInterceptor接口的类,需要重写intercept方法,用来拦截被代理类的方法调用。然后在该类中定义一个生产动态代理对象的方法,该方法接收被代理类的对象,然后拦截方法,设置调用拦截方法的逻辑,最后返回创建的动态代理对象。

CGLib动态代理的总结

1.CGlib动态代理的原理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理。 因为动态代理类是继承自业务类,所以该类和方法不能声明成final(无法继承或重写)。

2.同JDK动态代理一样,CGLib动态代理也无法做到对业务类的每个方法都实现不同的拦截逻辑。

JDK动态代理和CGLib动态代理的比较

1.JDK动态代理是面向接口,在创建代理实现类时比CGLib要快,创建动态代理类的速度快。

2.CGLib动态代理是通过字节码底层继承要代理类来实现(如果被代理类被final关键字所修饰,那么会失败),在创建代理这一块没有JDK动态代理快,但是运行速度比JDK动态代理要快。

3.2者最终都是生成了一个新的动态代理类对象。

Spring中的动态代理 1、Spring在选择用JDK还是CGLiB的依据?

(1)当Bean实现接口时,Spring就会用JDK的动态代理。

(2)当Bean没有实现接口时,Spring使用CGlib实现。

(3)可以强制使用CGlib(在spring配置中加入

2、CGlib比JDK快?

(1)在对JDK动态代理与CGlib动态代理的代码实验中看,1W次执行下,JDK7及8的动态代理性能比CGlib要好20%左右。

(2)使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/77268.html

相关文章

  • JAVA代理模式的理解和应用

    摘要:代理模式代理模式通俗一点的解释就是在操作一个对象和对象中的方法时,不是直接操作这个对象,还是通过一个代理对象来操作这个实际的目标对象。 代理模式: 代理模式通俗一点的解释就是在操作一个对象和对象中的方法时,不是直接操作这个对象,还是通过一个代理对象来操作这个实际的目标对象。应用场景一般是需要在执行某个已经写好的方法前后再添加一段逻辑,比如执行方法前打印日志,或者在执行方法之前和之后打时...

    CatalpaFlat 评论0 收藏0
  • 【干货】JDK动态代理的实现原理以及如何手写一个JDK动态代理

    摘要:代理模式从类型上来说,可以分为静态代理和动态代理两种类型。然而今天的重点是我们都知道牛逼轰轰的的实现的一种方式是使用的动态代理另一种是,大部分人也会用的动态代理,不过没有研究过的动态代理到底是怎么实现的。 动态代理 代理模式是设计模式中非常重要的一种类型,而设计模式又是编程中非常重要的知识点,特别是在业务系统的重构中,更是有举足轻重的地位。代理模式从类型上来说,可以分为静态代理和动态代...

    forsigner 评论0 收藏0
  • Java的三种代理模式

    Java的三种代理模式 参考:http://www.cnblogs.com/cenyu/...Java核心技术原书第九版6.5节 为什么使用代理   我们在写一个功能函数时,经常需要在其中写入与功能不是直接相关但很有必要的代 码,如日志记录,信息发送,安全和事务支持等,这些枝节性代码虽然是必要的,但它会带来以下麻烦: 枝节性代码游离在功能性代码之外,它不是函数的目的,这是对OO是一种破坏 枝节性...

    Rango 评论0 收藏0
  • 动态代理

    摘要:定义代理设计模式为其他对象提供一种代理以控制对这个对象的访问。动态代理代理类在程序运行时创建的代理方式被成为动态代理。 1.定义 代理设计模式:为其他对象提供一种代理以控制对这个对象的访问。动态代理:代理类在程序运行时创建的代理方式被成为 动态代理。代理类并不是在Java代码中定义的,而而是在运行时根据我们在Java代码中的指示动态生成的 2.简介 Sping mvc的Aop就是基于动...

    FWHeart 评论0 收藏0
  • 人人都会设计模式:代理模式--Proxy

    摘要:话说谁还干类似的事,就在文章末尾点个赞代销店等其实就是现在的商店,以前小的时候听家乡人叫代销店,也是一种代理模式。可以说是系统中最重要的架构之一。 showImg(https://segmentfault.com/img/remote/1460000012278678?w=1240&h=469); PS:转载请注明出处作者: TigerChain地址: http://www.jians...

    tuniutech 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<