cglib动态代理 | 拦截器

news/2024/11/9 2:54:30/

文章目录

    • 一、代理方法长什么样
      • 代码示例:
    • 二、代理方法逻辑
    • 三、代理对象初始化过程
    • 四、总结





一、代理方法长什么样


代码示例:

//被代理类
class UserService {//方法必须能被重写,不能被final修饰public void test() {System.out.println("调用test方法了...");}
}//拦截器(方法增强)
class MyApiInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("被代理方法执行前"); // 此处可以做一些操作Object result = proxy.invokeSuper(obj, args);//执行被代理方法System.out.println("被代理方法执行后" );  // 方法调用之后也可以进行一些操作return result;}
}//测试
public class TestCglib {public static void main(String[] args) {//生成一个增强器Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserService.class); //设置要代理的类enhancer.setCallback(new MyApiInterceptor()); //设置回调的拦截器// 创建代理对象Person person=enhancer.create();person.test();}
}





  刚开始接触动态代理,设想的代理方法是如下的样子,是不是很简单粗暴,这么想是不是也挺合理。
在这里插入图片描述
  其实代理方法长这样:
  下面的test方法就是生成的代理方法,其中没有我们写的增强代码,也没有用super.test()去调用被代理方法,而是先获得一个拦截器,然后执行intercept()方法。
在这里插入图片描述


既然代理类是运行时自动生成的,为什么不直接把增强代码粘到代理方法中?

  行,但是不优雅。

  拦截器提供了一种可插拔的方式,使增强逻辑与目标方法解耦,能够灵活地对代理逻辑进行配置和管理。

  看看拦截器是如何起作用的。





二、代理方法逻辑


  从上面的例子看,我们调用代理对象的test方法,是如何去执行拦截器【MyApiInterceptor类】中的逻辑呢?
  这要看代理类重写的test方法做了写什么:

在这里插入图片描述



  从程序执行的结果上看,图上MethodInterceptor的实现类就是我们自定义的MyApiInterceptor,这里需要说明一下intercept方法的四个参数都是什么:

  • 参数1:代理类对象
  • 参数2:被代理类的方法对象(Method类型对象)
  • 参数3:方法入参(Object[])
  • 参数4:代理类的方法对象(MethodProxy类型对象)
    在这里插入图片描述

  代理方法如何得到我们自定义的MyApiInterceptor对象?

MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;

  上面是test()方法的第一句代码,其中的(CGLIB$CALLBACK_0)属性是MethodInterceptor类型的,自定义的MyApiInterceptor正好实现了MethodInterceptor接口,这里明显是使用了里式替换。

  看哪里给(CGLIB C A L L B A C K 0 )属性赋值了,可以找到构造函数中挑中了【 C G L I B CALLBACK_0)属性赋值了,可以找到构造函数中挑中了【CGLIB CALLBACK0)属性赋值了,可以找到构造函数中挑中了【CGLIBBIND_CALLBACKS方法】,内容如下:

	//代理类构造函数public UserService$$EnhancerByCGLIB$$9391ced0() {CGLIB$BIND_CALLBACKS(this);}

在这里插入图片描述
  现在我们需要知道什么时候在缓存(CGLIB$THREAD_CALLBACKS属性)中存了自定义的MyApiInterceptor对象。

   在代理类中只找到一个静态方法【CGLIB$SET_THREAD_CALLBACKS】给上述属性赋值了,没有在本类中看到谁调用了这个方法。

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {CGLIB$THREAD_CALLBACKS.set(var0);}

  所以我们要知道,是谁在什么地方调用了静态方法【CGLIB$SET_THREAD_CALLBACKS】




三、代理对象初始化过程


  从demo中看出,创建代理对象是通过enhancer.create();创建的,需要从【Enhancer 类】的【create方法】开始抽丝剥茧找到真相。看个源码和破案一样。

		//生成一个增强器Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserService.class); //设置要代理的类enhancer.setCallback(new MyApiInterceptor()); //设置回调的拦截器// 创建代理对象Person person=enhancer.create();

在这里插入图片描述
  方法【createUsingReflection】的第一句代码调用了方法【setThreadCallbacks】,并把代理类的Class对象传给了它。这个方法名的意思就是给ThreadCallbacks赋值,下图看该方法逻辑

在这里插入图片描述
  这里确定方法名SET_THREAD_CALLBACKS_NAME就是代理类中的静态方法【CGLIB$SET_THREAD_CALLBACKS】。另外因为是静态方法,反射调用时不用传递代理类对象,传个null就可以。


  标题2中我们的问题我们在这里就可以揭晓。

  是谁在什么时候调用了静态方法【CGLIB S E T T H R E A D C A L L B A C K S 】,给( C G L I B SET_THREAD_CALLBACKS】,给(CGLIB SETTHREADCALLBACKS】,给(CGLIBTHREAD_CALLBACKS属性)中存了自定义的MyApiInterceptor对象?

  who:Enhancer对象
  when:在创建了代理类之后,马上要生成代理类对象之前




四、总结


  CGLIB拦截器的作用主要有以下几个方面:

  1. 增加额外的逻辑:
      拦截器可以在目标方法执行前后,或者在方法执行过程中插入额外的逻辑。例如,可以在方法调用前进行权限检查、日志记录等操作,或者在方法调用后进行结果处理、异常处理等操作。通过拦截器,可以在不修改目标类的情况下,增加额外的功能。

  2. 实现横切关注点的分离:
      拦截器可以将与核心业务逻辑无关的横切关注点(cross-cuttingconcern)与核心业务逻辑分离。横切关注点包括日志记录、性能统计、事务管理等,这些功能可以通过拦截器统一管理,而不需要在每个目标方法中重复编写代码。

  3. 实现代理的灵活配置和管理:
      拦截器提供了一种可插拔的方式,使得增强逻辑可以与目标方法解耦,方便对代理逻辑进行配置和管理。通过拦截器,可以动态地添加、删除或修改代理逻辑,而无需修改目标类的源代码。

  CGLIB拦截器的作用是在代理类中插入增强逻辑,实现与目标方法的拦截、预处理和后处理操作,同时实现了横切关注点的分离和代理的灵活配置。它是CGLIB实现动态代理的重要组成部分,提供了一种强大的方式来扩展和定制代理类的行为。


http://www.ppmy.cn/news/673916.html

相关文章

机房工程主要施工方法和机房工程验收

一、主要施工方法 (一)建筑装饰装修工程施工方法 l.轻钢龙骨石膏板隔墙 (1)工艺流程:放线→安装沿顶龙骨和沿地龙骨→安装竖向龙骨→安装横向龙骨安装石膏板(罩面板)→石膏板(罩面板)面层施工。  (2)操作要点。  1)放线。根据施工图纸,在隔断上、下基体连接处&a…

一、HTML基础标签

目录 1.HTML简介 2.HTML标签 3.HTML基础标签 4.标签分类 1.HTML简介 超文本标记语言(英语:HyperText Markup Language,简称:HTML)是一种用于创建网页的标准标记语言 标记语言是一套标记标签 HTML 使用标记标签来…

nvdiffrecmc在Windows上的配置及使用

nvdiffrecmc是NVIDIA研究院开源的项目,源代码地址:https://github.com/NVlabs/nvdiffrecmc,论文为《Shape, Light, and Material Decomposition from Images using Monte Carlo Rendering and Denoising》,使用Monte Carlo渲染和去…

家电维修——修空调潜规则

由于家电市场的特殊性,路边“黑售后”的猖獗让市场也更加混乱性,而很多消费者因缺少正确的保护意识而让不法人员钻空子,导致天价收费现象的发生。据了解,空调、冰箱、洗衣机在遭遇不正规军的售后服务时,高收费是屡屡发…

C++ 实现的多生产者和多消费者的lock-free 队列

C 实现的多生产者和多消费者的lock-free 队列 flyfish 源码下载地址 一共 20个线程&#xff0c;10个是生产者 10个是 消费者 #include <iostream> #include <concurrentqueue.h> using namespace moodycamel; using namespace std;int main() {cout << &q…

python gui 可视化开发工具_朋友邀请为领英好友什么意思

朋友邀请为领英好友什么意思考但是鼓励去思很少孩子&#xff0c;朋友我、鼓励去探自我很少孩子发现索自。 她的条件完全符合&#xff0c;邀请英好友。她觉得她种自了这由失去&#xff0c;为领但工作后。 体制但也单位工作而非只是离开&#xff0c;朋友的想离开叶雨有过法。把这…

为什么grab显示无法定位_为什么我在领英上搜到的客户都是显示领英会员(Linkedin Member)?也无法添加领英好友?...

LinkedIn领英上找客户&#xff0c;开发客户已经越来越成为主流&#xff0c;但是很多刚注册使用LinkedIn领英的人会摸不着头脑&#xff0c;束手无策。 因为他会发现自己搜索出来的结果&#xff0c;找出来的客户都是显示领英会员&#xff08;Linkedin Member&#xff09;&#xf…

领英几度的含义

使用领英的人都肯定发现过一个现象&#xff0c;每个好友姓名右侧都会显示1度或2度或3度的标识&#xff0c;这些都分别是什么意思呢&#xff1f; 解释这个之前&#xff0c;首先科普一下领英的基本知识。领英是一个关系型职业社交平台。这里有个重要的特征——“关系“&#xff0…