谈谈SpringAop代理

系列文章目录

一、什么是AOP?

一般称为面向切面编程,是作为面向对象的一种补充(面向对象是纵向扩展,AOP是横向扩展),用于处理系统中分布于各个模块的横切关注点,比如处理事务管理、日志、缓存、异常等等
aop实现的关键是在于AOP框架自动创建的AOP代理对象,AOP代理主要分为静态代理(AspectJ)和动态代理Spring AOP(JDK,CGLIB)

二、AOP织入的几种方式

切面织入方式3种
1、编译期织入:如AspectJ
2、类装载织入:CGlib
3、动态代理织入:在运行期为目标类添加增强生成子类的方式,SpringAOP采用动态代理织入切面。

1.AspectJ静态织入:

实现方式:需要定义接口或父类,被代理对象和代理对象一起要实现相同的接口或继承相同父类
使用AspectJ的编译时增强实现AOP
AspectJ是静态代理的增强,静态代理就是AOP框架会在编译的阶段生成的AOP代理,因此可以称为编译时增强。
优点:AspectJ静态织入不需要生成代理对象,任何类都可以进行织入,即使final修饰的类也可以进行织入,不需要进行bean配置和创建代理对象(srpingAOP方式需要)。
缺点:1、使用AspectJ比较繁琐,下载安装,配置环境,编译织入代码运行代码等步骤;
2、当接口方法增多时,目标对象和接口对象都需要维护
3、如果目标类的方法过多,在给代理类中加业务时会造成代码冗余
4、硬编码,不易扩展,难维护

2.JDK动态代理:

优势:在于可以很方便的对代理类的函数进行统一处理,而不用修改每个代理类中的方法。是因为所有被代理执行的方法,都是通过InvocationHandler中的invoke方法调用,我们只需要对invoke方法中统一处理,就可以对所有被代理对象进行相同的操作。SpringAOP代理中JDK动态代理用到了Proxy类和InvocationHandler
InvocationHandler:传入被代理对象生成执行句柄;
Proxy:通过newProxyInstance方法传入 句柄生成代理对象:

总结:与静态代理相比,JDK动态代理中代理对象不要实现接口,而目标对象必须实现接口
优点:经典应用在Spring aop代理中,只要一个代理方法就能代理所有的目标对象
缺点:JDK动态代理是接口代理,只能代理接口对象中的所有方法,实现类中自定义的方法是不能被代理的,因为生成代理对象的时候newProxyInstance时,传入的是接口类型。这时候需要CGLIB动态代理。可以实现本类所有方法的代理。

3.CGLIB(字节码生成库)动态代理:

上面的静态代理和动态代理都需要目标对象是实现一个接口的目标对象,但目标对象有时候只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象类的子类的方式实现代理,叫CGLIB代理。
原理:在生产的代理类中,对于父类的中每一个能够继承重写的方法,动态代理都会生成两个对应的方法;一个是直接重写父类的方法,一个是生成对应的动态代理的方法,在调用时候会先调用重写的方法。执行代理类中的方法,实际执行的是被代理类的方法。

CGLIB原理 4步骤:
1、首先生成代理对象【创建增强类enhancer,设置代理类的父类(目标类),设置回调拦截方法,返回创建代理对象】
2、调用代理类中的方法【这里调用的代理类中的方法实际是重写的父类的拦截,重写的方法会调用intercept方法】
3、调用intercept方法,方法中会调用代理方法中的invokeSuper方法。invokeSuper方法中维护了一个FastClassInfo,其中包含4个字段,分别是FastClass f1(目标类),FastClass f2(代理类),int i1(目标类要执行方法的下标),int i2 (代理类要执行方法的下标); invokeSuper中会调用代理类中的生成的代理方法(先前调用的是调用目标类重写的方法)
4、调用代理类中的代理方法,会通过super.method会调用实际类中该执行的方法。
注意:1、目标类不能为final修饰
2、目标对象的方法为final/static不会被拦截

JDK和CGLIB优缺点:
JDK代理生成的代理类只有一个,因此在编译的时候速度非常快;而被代理的目标类是动态传入代理类中的,所以JDK动态代理执行的时候效率相比CGLIB效率低一点,这也是JDK代理被称为动态代理的原因,主要通过反射实现。
CGLIB代理需要为每个目标类生成相应的子类,因此在实际运行过程中,可能会生成非常多子类,过多的子类始终不太好,因此这也影响了虚拟机编译类的效率;但在调用过程中,代理类的方法已经是静态编译生成了的,所以CGLIB执行效率相对较高,主要通过继承来实现。

springAOP和AspectJ区别:
1、织入时期不同:SpringAOP采用动态织入,AspectJ采用静态织入。
静态织入:指编译时期就织入,即class文件编译出来,就已经织入成功了。
动态织入:又分静/动两种
静:织入过程只在第一次调用时执行;
动:根据代码动态运行中的中间状态来决定如何操作,每次调用目标的时候都会执行。

2、使用对象不同:
Spring AOP的通知是基于该对象是SpringBean对象才可以,而AjspectJ可以再任何java对象上应用通知。
Spring AOP:如果想要通过this对象调用的方法上进行通知,那么必须要使用currentProxy对象,并调用其相应的方法;与此类似,如果想调用某对象的方法上进行应用通知,那么必须使用该对象相对应的spring bean,springAOP与IOC之间紧密集成。
AspectJ:使用Aspect的一个间接局限是,因为AspectJ通知可以应用到pojo上,它有肯能将通知应用于已配置的通知上。对于一个没有注意到这方面问题的大范围应用的通知,这有可能导致一个无限循环。

springAOP何时会使用JDK动态代理,何时使用CGLIB代理?
Spring AOP在使用上,也进行了自动的调整,当有接口时,会自动选择JDK动态代理技术,如果没有则选择CGLIB动态代理。springAOP内部实现了一个专注于生成代理类的工厂类,这样避免了大量的手动编码,这是spring动态代理的核心技术。

SpringAOP与AspectJ之间如何选择:
明确在应用横切关注点时(事务管理,日志,性能评估,权限等),需要处理的是springbeans还是POJO。如果正在开发新的应用,则选择Spring AOP就没有什么阻力;但是你正在维护一个现有的应用(该应用没有用spring框架),AspectJ将是一个自然的选择。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值