Spring的AOP框架

对于Spring的IOC虽说博客写的比较拉跨,但是学得得还是很多哒.如今进入了AOP了,也不希望自己再继续贴大段的源码去分析,从此篇开始,减少贴在博客的源码,咱们多打字,文风也轻松愉快点,不然都快没写博客的动力了,此篇主要是谈一谈spring的AOP框架

AOP的思想

AOP中文翻译为面向切面编程,这是一种思想.所以它并不是spring独有的,spring只是通过代码去实现了这个东西.弥补了java不能横向编程的遗憾,横向是个怎么样的概念呢?总所周知,java的封装继承多态是纵向的一种拓展,如下图所示,发财的类是可以不断的扩充的
在这里插入图片描述
但是如果要在所有的发财类中加入一个前提条件比如都需要先受过九年义务教学,那么就有点累了,如下图所示.以后拓展也是需要经过九年义务教学的.
在这里插入图片描述
对于这样横向的代码逻辑的添加,就需要AOP的思想去实现,用一个办法让横向的代码添加更加优雅,为了让业务代码和技术代码进行分离.spring的aop底层实现是运用了动态代理模式(dubbo貌似是使用了装饰者模式实现了他自己的aop)

AOP的实现

Spring的aop是通过动态代理去实现的,通过验证某实例是否符合被代理的条件,去返回代理对象还是实例对象.
一个被spring管理的实例对象,在被实例化和填充完对象以后,会被它的BeanPostProcessor接口集合给处理一下,在众多的BeanPostProcessor中,有一个专门服务于代理的抽象入口类AbstractAutoProxyCreator,如果是基于注解的AOP的话.
需要在启动类上添加@EnableAspectJAutoProxy 这个注解的话,会注入一个注解解析的代理入口类
AnnotationAwareAspectJAutoProxyCreator看下它的继承类图在这里插入图片描述
那么必然会执行BeanPostProcessorpostProcessBeforeInstantiationpostProcessAfterInitialization方法.

postProcessBeforeInstantiation和postProcessAfterInitialization方法都隶属于AbstractAutoProxyCreator这个类,在其子类中没有对这两个方法进行重写的操作,所以所有的代理的开始都会进入这里.

postProcessAfterInitialization是对代理方法的收集和是否需要代理的判定以及对代理的生成和返回

重要的补充: spring对AOP的增强(advice)切入点(pointCut)是封装成了一个对象的,叫advisor. postProcessAfterInitialization其实就是对spring容器中所有advisor的收集以及检索出来目标类能被增强的advisor

在这里插入图片描述
当然在注解的配置中也会对spring的几大注解进行扫描,收集,解析最后封装成一个advisor
@Before, @After, @Around,@AfterReturning,@Pointcut,@Aspect
每个注解都是不一样的一个advice实现,通过类是否加了@Aspect的去检索,然后通过表达式解析匹配,是否符合代理规则

AbstractAdvisorAutoProxyCreator中的收集则是对advisor的类进行的一个收集了,
收集的方法叫做findCandidateAdvisors(),在AnnotationAwareAspectJAutoProxyCreator中重写了该方法,同时也调用了父类AbstractAdvisorAutoProxyCreator的该方法.

收集完advisor后,还需要进行筛选,比如说事物切面需要校验类或者方法有加@Transactional注解,缓存切面需要校验@Cacheable等注解。如果你是通过@Aspect注解生成的advisor则需要通过解析表达式的语义去进行匹配,在Spring的aop框架中,能够去做校验的便是切入点(Pointcut接口),在Pointcut接口中有ClassFilterMethodMatcher这两个接口,其中ClassFilter负责类的校验而MethodMatcher负责做方法的校验。

总结一下流程如下
在这里插入图片描述

AOP的执行

当一个bean历经千辛万苦,终于被代理以后,还有一段路是需要走的,这就是该代理类的执行

spring的aop呢是有两种代理模式,其一是JDK的动态代理去实现,其二是通过cglib的动态代理去实现。具体使用谁实现是可配置的,默认情况下Spring是会使用jdk的动态代理,然而如果遇到jdk无法代理的情况,例如,被代理者无接口上级时,spring会自动切换成cglib的动态代理去生成代理类,其中的这个参数变量名叫:proxyTargetClass

本博客以jdk的代理为思路去阐述代理类的执行过程(因为笔者只知道jdk的动态代理,妥妥的菜鸡一只啊T_T)

首先对于jdk的动态代理,需要有一个实现InvocationHandler的类,这个类的invoke方法中有对代理过程的实际逻辑处理的。
在spring中,这个类叫做JdkDynamicAopProxy

具体的调用逻辑是这样的,比如靠富婆发财的类有个发财方法,当然现在要在这个发财方法执行前加入九年义务教育过程,如果我们已经通过spring的注解方式@Before生成了一个Advisor的通知,并且生成了一个代理类。那么这个代理类的样子呢简单上来说是这样子的
在这里插入图片描述
当执行invoke方法时候会把这里面的Advisor的集合给再次做一下过滤,匹配符合该方法的Advisor,比方说:这个类中有事务和缓存两个切面,但是在不同方法上,这两个切面的Advisor都会在生成的代理对象的Advisor集合中。所以第一步会筛选出来适应该方法的Advisor们,之后通过各种信息生成一个专门执行该发财方法的类ReflectiveMethodInvocation在这里插入图片描述
这个类的proceed()方法便是AOP执行的开端
这个方法它到底干了什么事情呢?
首先,该类将代理中的Advisor集合封装成了不同的MethodInterceptor给带了进来,这些MethodInterceptor是有排序的,首先呢,是所有的加入到spring中的Advisor是比通过注解生成的Advisor靠前的,然后通过注解生成的呢也是有顺序的,这个顺序呢也是保证@Before, @After, @Around,@AfterReturning等注解执行的逻辑的。具体的顺序是在这里插入图片描述
proceed()里面有个坐标属性从-1开始,每次加1。直到这个坐标值等于MethodInterceptor的size。否则就会执行对应的MethodInterceptor的
invoke方法。
在所谓的众多MethodInterceptor中都是会回调ReflectiveMethodInvocation的proceed()方法,一步一步传递下去,做出这样的设计我觉得主要还是比较多的考虑到了注解的功能的
从上图中会先进入@Around里面,但是想要火炬传递下去,则在我们定义的@Around的方法下,得有入参ProceedingJoinPoint的并且在方法中调用proceed(),类似这样在这里插入图片描述
ProceedingJoinPoint中有ReflectiveMethodInvocation属性,之后执行其实就是ReflectiveMethodInvocation的proceed()。如果不加该入参,因为火炬无法传递,所以最后连方法里面也不会执行。

而在其他注解中都会有对ReflectiveMethodInvocation的proceed()的调用。最后当所有的MethodInterceptor都执行完了,会使用发射把原本的方法执行下,由于其他注解中都会有对ReflectiveMethodInvocation的proceed()的调用,所以这是一个递归操作,最后返回的时候是层层返回的,返回后执行各自的代码,这也是@After等注解的工作原理,先把方法执行完,递归结束返回到自己的时候,再执行需要后置执行的人代码就阔以了。
总结就是如下图啦。
在这里插入图片描述

AOP的实战

原理讲讲讲,实战也要练练练!其实AOP的实战有两种,基于注解的实战相信还是比较多的,所以我们来试试其他的AOP吧,比如说自己做一个异步的注解玩玩。
大体的要求就是:实现一个注解,加了该注解的方法,会被另一个线程执行。
通过本篇博客的理解,首先得实现一个Advisor类。在spring中最好是实现AbstractPointcutAdvisor会比较方便.AbstractPointcutAdvisor也是Advisor的子类。
在这里插入图片描述
之后就是里面的属性了,pointCut已经定义好了,所以还需要实现三个类
Advice:具体增强
ClassFilter:类过滤
MethodMatcher:方法过滤
Advice的实现,实现MethodInterceptor更加方便,该类中内置一个线程池,并且对方法使用了线程池进行反射调用
在这里插入图片描述
ClassFilter的判定主要是看类里是否有方法有ZKAsy注解
在这里插入图片描述
MethodMatche中是对方法上是否有ZKAsy注解
在这里插入图片描述最后执行下看下结果
能够被线程池执行。圆满结束~~。
在这里插入图片描述
当然在这里也踩了坑,就是在MethodMatche的实现中,需要使用**AopUtils.getMostSpecificMethod(method, targetClass)**去取方法。不然第二次的方法是通过不了的原因是两次进入到这个MethodMatche中的类是不一样的,第一次是加了注解的实现类的方法,第二次是注解的方法,除非在注解上加否则肯定找不到注解啊。使用AopUtils.getMostSpecificMethod(method, targetClass)就可以拿到加了注解的实现类啦~~。

spring的Aop框架的基本实现思路应该已经阐述清楚了。掌握了aop的思路,以后在使用aop还是去阅读事务切面,缓存切面,异步切面都是有极大帮助的,学无止境,与君共勉!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值