前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >聊聊Java动态代理(下)

聊聊Java动态代理(下)

作者头像
Bug开发工程师
发布2018-04-17 13:28:58
5980
发布2018-04-17 13:28:58
举报
文章被收录于专栏:码农沉思录

前言

在之前的文章《聊聊Java动态代理(上)》中,笔者为大家介绍了Java原生的动态代理,并指出Java原生的动态代理有一个缺点就是被代理类必须显示地实现某个接口,否则无法正常使用,此局限性限制了Java原生动态代理的使用场景。幸好在Java生态中,实现动态代理的方式除了Java原生的动态代理,还有其他方式,本文将为大家介绍Java中另一种常见的动态代理实现方式——CGLib动态代理。

CGLib动态代理

CGLib是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为Java原生的动态代理提供了很好的补充。通常可以使用Java原生的动态代理创建代理,但如果要代理的类没有实现接口或者为了更好的性能,CGLib是一个好的选择。

使用CGLib动态代理

我们还是以前面的文章《聊聊Java动态代理(上)》中的用户登录功能为例,不清楚的朋友可以回过头先浏览一下该文章。

我们先实现基本登录功能:

BaseLoginService类只有一个login方法,默认所有用户都可以进行正常登录。注意该类与之前的文章《聊聊Java动态代理(上)》里的LoginServiceImpl的区别是LoginServiceImpl实现了LoginService接口,而BaseLoginService类并没有实现任何接口或者显示地继承某个类。

接下来我们定义我们的代理逻辑:

我们的代理逻辑是通过实现MethodInterceptor接口并实现intercept方法来实现的。在intercept方法的实现中,我们先对userId进行过滤,如果符合条件就继续调用正常的登录逻辑,否则就禁止用户登录。

然后我们还需要一个能够创建代理对象的功能:

代理类的创建需要使用Enhancer,其需要设置被代理对象的父类,由于被代理对象没有显示继承某个类,所以这里设置为被代理类本身就可以了。然后还需要设置代理逻辑,也就是上述LoginAdvice类的实例。

最后写一个客户端测一下:

其结果输出如下:

可以看到,使用CGLib我们也能实现动态代理。而且被代理类BaseLoginService并没有实现任何的接口,这一点是CGLib相对于Java原生动态代理的优势。但是CGLib对被代理类有没有其他要求呢?我们先来看下CGLib生成的代理类有什么特点,我们可以写一个客户端将该代理类的信息打印出来一探究竟。

我们将代理类的名称,还有其实现的接口以及继承的父类都打印出来,结果输出如下:

可以看到该类的名称并不是我们定义的,说明是在运行时产生的。其接口是net.sf.cglib.proxy.Factory,这是CGLib库中的一个接口。再看其父类是我们定义的BaseLoginService类,也就是说CGLib是通过继承被代理类来生成代理类,进而实现动态代理的。既然CGLib代理类是通过继承被代理类来生成的,那么如果被代理类的方法是final或者被代理类是final的还能不能实现代理逻辑呢?我们试一下就知道了。

首先我们将BaseLoginService类的login方法声明为final,代码就不贴出来了,我们直接看结果:

可以看到,客户端代码正常运行,只是这个时候已经没有了我们定义的代理逻辑了,“user1”和“user2”都正常登录了,因此如果被代理类的方法声明为final,CGLib是不能织入代理逻辑的。

接下来我们把BaseLoginService类声明为final试试看,同样我们看结果就行了:

可以看到,客户端代码直接报错了,所以如果被代理类被声明为final,CGLib会直接报错。

以上就是CGLib动态代理的全部内容了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-02-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农沉思录 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档