SpringAOP实现:(一)横切逻辑的加载与解析
横切逻辑的加载与解析:
即Aspect和Advice的加载阶段,在后续创建动态代理的时候, 根据之前开发自研框架AOP的经验,需要拿着所有的Aspect去尝试与容器的业务Bean去做匹配,只有匹配的Aspect才会去创建对应的动态代理,SpringAOP也不例外。
而进行匹配前势必要把IOC容器所有的Aspect和对应的Advice都加载好并缓存起来,随后才可以遍历所有的横切逻辑去做相关的匹配工作。
TargetSource:
TargetSource关系图:
首先可以看到TargetSource类实现了TargetClassAware接口,使之能够获取到对象实例。
SingletonTargetSource:用来确保被代理的实例是单例的。被代理的对象会被缓存到Object类型的target成员变量中。
PrototypeTargetSource:被代理的实例是多例的。
AbstractAutoProxyCreator:
横切逻辑的加载主要是在postProcessBeforeInstantiation方法中。该方法的调用时机是在bean的实例化之前调用的(详细可打上断点debug查看)
AbstractAutoProxyCreator.postProcessBeforeInstantiation():
方法是针对容器里的每个bean都会执行的,会去判断bean是否是Aspect。为了防止重复执行Aspect的加载,一般情况下都会引入缓存。缓存一般就是通过键位来定位到对应的缓存,这里也不例外。
(1)计算出键位来,调用了getCacheKey()方法去获取缓存里的key。
(2)查看传入的beanName为空 || targetSourcedBeans不包含beanName则进入if(这里的targetSourcedBeans是类内部的缓存,只提供类自己使用)
(A)判断如果beanName已经做过解析了则跳过
(B)判断当前bean是基础类型 || shouldSkip() shouldSkip()会调用findCandidateAdvisors()获取到容器中所有被@Aspect标记的bean然后逐一遍历如果是AspectJ的且名字跟我们传入的相符返回true
findCandidateAdvisors()方法:当你在使用注解方式配置AOP的时候该方法使之能够支持对XML配置的AOP的支持的(会将从注解方式获取到的Advisor和父类中获取到的xml配置的Advisor合并在一起)(找到所有Advisor的实例Bean们)
(a)调用父类的findCandidateAdvisors()从父类中获取Advisors
(b)调用成员变量aspectJAdvisorsBuilder的buildAspectJAdvisors()方法提取所有的Advisors然后跟(1)中获取的进行合并后返回所有的Advisors
findCandidateAdvisors方法下的buildAspectJAdvisors方法执行流程
(1)从容器获取所有的beanName(2)遍历beanName,解析出被@Aspect标记的类
(3)提取Aspect类的Advisors(这里调用了getAdvisors()方法,该方法会对Aspect里的所有方法除了pointcut,进行顺序的排序)(4)将提取的结果加入缓存
跟进到getAdvisors()方法中,该方法会对Aspect里的方法除了pointcut进行解析排序。
(A)获取到Aspect的类Class和类名字 (B)校验切面类 (C)创建出懒加载单例切面实例化工厂装饰者类 (D)获取到切面类中的所有方法(除@PointCut注解的方法) (排序过的)
(E)对获取到的方法进行循环解析。循环解析的getAdvisor().getPointcut().AspectJExpressionPointcut类,该类中提供了对Class级别和Method的匹配支持
(3)获取用户自定义的targetSource,如果存在则直接在对象实例化之前进行代理创建,避免了目标对象不必要的实例化(用户自定义的bean替代掉即将创建的bean)
如果获取到了用户自定义的targetSource实例,那么会去走后续的AOP的创建动态代理流程:
(A)获取到该bean对应的Advisors对象列表
(B)调用createProxy()创建除代理实例后返回代理的对象