目录java
1. findCandidateAdvisorsspring
2. buildAspectJAdvisorsexpress
2.1. 建立一个MetadataAwareAspectInstanceFactory对象数组
bean建立过程当中,在createBean步骤的resolveBeforeInstantiation中会调用beanPostProcessor处理器执行各自的postProcessBeforeInstantiation方法。在Spring在引入了AOP的状况下,后置处理器会多出一个AnnotationAwareAspectJAutoProxyCreator。在建立bean进行到该步骤的时候,该beanPostProcessor会在postProcessBeforeInstantiation方法中进行代理类Pointcut,JointPoint,Advice,Advisor的解析和缓存。为后续初始化bean中实现bean的代理作好准备。post
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName); if (result != null) { return result; } } } return null; }
直接来看调用ibp.postProcessBeforeInstantiation(beanClass, beanName)的实现方法, ui
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) { // 若是是普通bean,则返回beanName,若是是FactoryBean,则返回加上前缀&的&beanName Object cacheKey = getCacheKey(beanClass, beanName); // 第一次进入时,targetSourcedBeans还未缓存有对象,故会进入。 if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) { // 若是this.advisedBeans有缓存值,说明该bean已经被解析过了,直接返回null就跳过了后续的解析 if (this.advisedBeans.containsKey(cacheKey)) { return null; } // 基础类不该该被代理 if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } } // 若是用户自定义了TargetSource,那么直接返回用户自定义的代理类。不然返回null,使得Spring框架能继续执行下去。 TargetSource targetSource = getCustomTargetSource(beanClass, beanName); if (targetSource != null) { if (StringUtils.hasLength(beanName)) { this.targetSourcedBeans.add(beanName); } Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } return null; }
首先getCacheKey是获取beanName,若是是FactoryBean,那么beanName是要加上前缀"&"。第一次进入时,if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName))确定是会进入的。若是advisedBeans有缓存值,说明该bean已经被解析过了,直接返回null就跳过了后续的解析,不然进入第二个if分支。第一个条件isInfrastructureClass()是判断当前bean类型是不是基础类型,若是是则不会被代理。基础类型有Advice.class,Pointcut.class, Advisor.class, AopInfrastructureBean.class这4种。关键的核心代码是在shouldSkip(beanClass, beanName)中,返回的结果用于判断是否要跳过解析。可是执行的过程却远远不是一句话能说明白的,咱们一块儿深刻剖析shouldSkip方法。(后续的getCustomTargetSource方法是返回用户自定义的代理类。若是没有定义就返回null,使得Spring框架能继续执行下去。这里后续再也不分析~)this
protected boolean shouldSkip(Class<?> beanClass, String beanName) { // findCandidateAdvisors最终会由BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans执行 List<Advisor> candidateAdvisors = findCandidateAdvisors(); // 找到的candidate中有beanName与AspectJPointcutAdvisor相同,也就是PointcutAdvisor的实现类,则不会进行做为代理的尝试。 for (Advisor advisor : candidateAdvisors) { if (advisor instanceof AspectJPointcutAdvisor && ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) { return true; } } // 根据ORIGINAL_INSTANCE_SUFFIX判断给定bean名称是“原始实例”类型,若是是就跳过代理的尝试。 return super.shouldSkip(beanClass, beanName); }
核心的步骤是findCandidateAdvisors,用于寻找和解析advisor。而后再找到的advisor们中判断是否能够跳过。有两种状况能够被跳过:1.AspectName恰好就是这个bean的name;2.这个bean是原始实例,原始bean的后缀有“.ORIGINAL”标志。
接下来咱们进入核心的findCandidateAdvisors方法分析:
protected List<Advisor> findCandidateAdvisors() { List<Advisor> advisors = super.findCandidateAdvisors(); // 合并全局的advisors后返回 if (this.aspectJAdvisorsBuilder != null) { advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; }
super.findCandidateAdvisors()会借助BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans执行,咱们直接来看findAdvisorBeans。
public List<Advisor> findAdvisorBeans() { String[] advisorNames = this.cachedAdvisorBeanNames; if (advisorNames == null) { // 从bean工厂中寻找Advisor.class,而且是单例类型的beanName advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false); this.cachedAdvisorBeanNames = advisorNames; } if (advisorNames.length == 0) { return new ArrayList<>(); } List<Advisor> advisors = new ArrayList<>(); for (String name : advisorNames) { if (isEligibleBean(name)) { if (this.beanFactory.isCurrentlyInCreation(name)) { // 若是正在建立就跳过 } else { try { advisors.add(this.beanFactory.getBean(name, Advisor.class)); } catch (BeanCreationException ex) { Throwable rootCause = ex.getMostSpecificCause(); if (rootCause instanceof BeanCurrentlyInCreationException) { BeanCreationException bce = (BeanCreationException) rootCause; String bceBeanName = bce.getBeanName(); if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) { continue; } } throw ex; } } } } return advisors; }
首先尝试从拿到缓存的advisors,若是没有缓存,那么就从bean工厂中尝试找出从bean工厂中寻找继承了Advisor.class接口的类,并过滤出单例类型的beanName返回。·若是项目中没有继承接口Advisor的bean,那么直接返回new一个了ArrayList返回。若是有继承Advisor接口的bean,那么就从bean工厂中实例化出来添加到advisors list中返回上层执行后续的代码。
下面咱们来看this.aspectJAdvisorsBuilder.buildAspectJAdvisors()的执行流程。
public List<Advisor> buildAspectJAdvisors() { // 仍是先从缓存中获取,第一次进来确定是为null List<String> aspectNames = this.aspectBeanNames; if (aspectNames == null) { synchronized (this) { aspectNames = this.aspectBeanNames; if (aspectNames == null) { List<Advisor> advisors = new ArrayList<>(); aspectNames = new ArrayList<>(); // 从bean工厂中拿出全部beanName String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Object.class, true, false); for (String beanName : beanNames) { // 判断这个bean是否能够作自动代理的可能 // 具体的判断依据是根据org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#includePatterns中 // 添加的规则进行过滤。默认是没有添加任何规则,也就是任何bean都有被代理的可能。 if (!isEligibleBean(beanName)) { continue; } Class<?> beanType = this.beanFactory.getType(beanName); if (beanType == null) { continue; } // 看看这个bean的类中是否有Aspect的注解,若是 // 好比OperationAop类中就含有这样的注解。第一次解析出注解后,会将其添加到AnnotationUtils的findAnnotationCache map中缓存 if (this.advisorFactory.isAspect(beanType)) { // 先添加到临时list中,后边会追加到this.aspectBeanNames中。 aspectNames.add(beanName); // 这里其实就是看这个bean是不是单例的。若是是单例的,那么它的代理bean也会是单例的,不然就看成是原型的。 AspectMetadata amd = new AspectMetadata(beanType, beanName); // aspect (perthis/target/cflow/cflowbelow)有这几种使用模式,我一个都没用过>.<!。 默认是SINGLETON if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { // 建立一个针对当前类型的一个单例的代理工厂 MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); // 解析和建立对应代理工厂的advisor List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory); // 放入BeanFactoryAspectJAdvisorsBuilder的缓存map advisorsCache中 if (this.beanFactory.isSingleton(beanName)) { this.advisorsCache.put(beanName, classAdvisors); } else { this.aspectFactoryCache.put(beanName, factory); } advisors.addAll(classAdvisors); } else { MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName); this.aspectFactoryCache.put(beanName, factory); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } } this.aspectBeanNames = aspectNames; return advisors; } } } if (aspectNames.isEmpty()) { return Collections.emptyList(); } List<Advisor> advisors = new ArrayList<>(); for (String aspectName : aspectNames) { List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName); if (cachedAdvisors != null) { advisors.addAll(cachedAdvisors); } else { MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } return advisors; }
进来首先仍是先从缓存中获取,第一次进来确定是为null。DCL检查this.aspectBeanNames是否已经有缓存。检查都经过之后,首先从bean工厂中拿出全部到beanNames中,而后遍历这些beanNames进行aop的相关解析。isEligibleBean(beanName)是判断这个bean是否能够作自动代理的可能,具体的判断依据是根据AnnotationAwareAspectJAutoProxyCreator#includePatterns中添加的规则进行过滤。默认是没有添加任何规则,也就是任何bean都有被代理的可能。advisorFactory.isAspect(beanType)是判断这个bean的类中是否有Aspect的注解,好比OperationAop.class类中就含有这样的注解。第一次解析出注解后,会将其添加到AnnotationUtils的findAnnotationCache map中缓存。随后根据PerClauseKind.SINGLETON分开处理单例与原型的advisorFactory。aspect (perthis/target/cflow/cflowbelow)有这几种使用模式,默认是SINGLETON。咱们只分析单例的状况,原型的大同小异留给读者自行分析吧。重点来看这三行代码:
//建立一个针对当前类型的一个单例的代理工厂 MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); // 解析和建立对应代理工厂的advisor List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory); // 放入BeanFactoryAspectJAdvisorsBuilder的缓存map advisorsCache中 if (this.beanFactory.isSingleton(beanName)) { this.advisorsCache.put(beanName, classAdvisors); } else { this.aspectFactoryCache.put(beanName, factory); } advisors.addAll(classAdvisors);
以OperationAop.class为例,对象中包含的信息以下:
beanFactory = DefaultListableBeanFactory name = "operationAop" aspectMetadata = {AspectMetadata@3331} 其中aspectMetadata: aspectName = "operationAop" aspectClass = "class com.Hodey.analyseaop.aop.OperationAop" ajType = "com.Hodey.analyseaop.aop.OperationAop" perClausePointcut = "Pointcut.TRUE"
this.advisorFactory.getAdvisors(factory) 解析和建立对一个代理工厂的advisor
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) { Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName(); validate(aspectClass); // 包装MetadataAwareAspectInstanceFactory一下,使得它只能被实例化1次 MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory); List<Advisor> advisors = new ArrayList<>(); for (Method method : getAdvisorMethods(aspectClass)) { // 尝试解析每一个方法,找到方法对应的切点和通知 Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName); if (advisor != null) { advisors.add(advisor); } } // 代理默认不是懒加载的,这里的分支通常不会走进 if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) { Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory); advisors.add(0, instantiationAdvisor); } // 若是属性也有须要代理的,那么还须要寻找到属性的advisor for (Field field : aspectClass.getDeclaredFields()) { Advisor advisor = getDeclareParentsAdvisor(field); if (advisor != null) { advisors.add(advisor); } } return advisors; }
建立LazySingletonAspectInstanceFactoryDecorator的目的仅仅是包装传入的MetadataAwareAspectInstanceFactory,使得它是单例对象。getAdvisorMethods(Class<?> aspectClass)是获取传入class及其继承类的全部方法,以OperationAop.class为例获取的方法集以下:
0 = {Method@3112} "public int com.Hodey.analyseaop.aop.OperationAop.doAround(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable" 1 = {Method@3512} "public void com.Hodey.analyseaop.aop.OperationAop.doBefore()" 2 = {Method@3513} "public void com.Hodey.analyseaop.aop.OperationAop.doAfter()" 3 = {Method@3514} "protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException" 4 = {Method@3515} "public boolean java.lang.Object.equals(java.lang.Object)" 5 = {Method@3516} "protected void java.lang.Object.finalize() throws java.lang.Throwable" 6 = {Method@3517} "public final native java.lang.Class java.lang.Object.getClass()" 7 = {Method@3518} "public native int java.lang.Object.hashCode()" 8 = {Method@3519} "public final native void java.lang.Object.notify()" 9 = {Method@3520} "public final native void java.lang.Object.notifyAll()" 10 = {Method@3521} "private static native void java.lang.Object.registerNatives()" 11 = {Method@3522} "public java.lang.String java.lang.Object.toString()" 12 = {Method@3523} "public final void java.lang.Object.wait() throws java.lang.InterruptedException" 13 = {Method@3524} "public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException" 14 = {Method@3525} "public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException"
而后对这些方法尝试获取它的advisor。
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) { // 得到切点 AspectJExpressionPointcut expressionPointcut = getPointcut( candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass()); if (expressionPointcut == null) { return null; } // 找到了切点,就将切点、链接点、通知等aop参数封装成InstantiationModelAwarePointcutAdvisorImpl对象向上返回。 return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName); }
首先要去找到切点。可是进入getPointCut后从方法名上看为何第一步竟然是去找对应方法上的注解呢?别着急,咱们跟着流程一步步分析:
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) { AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if (aspectJAnnotation == null) { return null; } AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]); // 由于aspectJAnnotation已经封装了切点pointcut的信息,因此直接拿出来设置到ajexp对象上便可。 ajexp.setExpression(aspectJAnnotation.getPointcutExpression()); if (this.beanFactory != null) { ajexp.setBeanFactory(this.beanFactory); } return ajexp; } protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) { for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) { AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz); if (foundAnnotation != null) { return foundAnnotation; } } return null; }
首先来看findAspectJAnnotationOnMethod方法。ASPECTJ_ANNOTATION_CLASSES中存放的是[Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class]数组。在for循环中会依次对方法上的注解和ASPECTJ_ANNOTATION_CLASSES中元素进行比对,找出对应注解的AspectJAnnotation。以OperationAop中的beforeAdd方法为例。该方法上有注解@Around("addCut()"),那么就会经过findAnnotation找到该注解, 在返回的结果中已经封装了切点位置,通知类型,切点的表达式和参数名等信息:
annotation = "@org.aspectj.lang.annotation.Around(argNames=, value=doCut())" annotationType = "AtAround" pointcutExpression = "doCut()" argumentNames = ""
而后建立AspectJExpressionPointcut ajexp对象,将findAnnotation找到的结果中封装的相关切点信息设置到ajexp对象上,随后将这个带有切点信息的对象返回上层getAdvisor方法,随后在该方法中将切点、链接点、通知等aop参数封装成InstantiationModelAwarePointcutAdvisorImpl对象向上返回到getAdvisors方法,随后将返回值添加到List<Advisor> advisors中。等到遍历完全部方法,将advisors一路返回,最终返回到buildAspectJAdvisors中在advisorsCache缓存好advisors对象再一路返回到shouldSkip,本步骤执行完成。
值得一提的是再InstantiationModelAwarePointcutAdvisorImpl对象建立过程当中会调用instantiateAdvice实例化通知(advice),这个过程当中会调用getAdvice方法建立通知。
public Advice getAdvice(Method candidateAdviceMethod是, AspectJExpressionPointcut expressionPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); validate(candidateAspectClass); AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if (aspectJAnnotation == null) { return null; } AbstractAspectJAdvice springAdvice; //根据不一样的注解,就会走不一样的分支建立各自的通知对象 switch (aspectJAnnotation.getAnnotationType()) { case AtPointcut: return null; case AtAround: springAdvice = new AspectJAroundAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtBefore: springAdvice = new AspectJMethodBeforeAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfter: springAdvice = new AspectJAfterAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfterReturning: springAdvice = new AspectJAfterReturningAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterReturningAnnotation.returning())) { springAdvice.setReturningName(afterReturningAnnotation.returning()); } break; case AtAfterThrowing: springAdvice = new AspectJAfterThrowingAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterThrowingAnnotation.throwing())) { springAdvice.setThrowingName(afterThrowingAnnotation.throwing()); } break; default: throw new UnsupportedOperationException( "Unsupported advice type on method: " + candidateAdviceMethod); } // 最后再手动设置一些属性。 springAdvice.setAspectName(aspectName); springAdvice.setDeclarationOrder(declarationOrder); String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod); if (argNames != null) { springAdvice.setArgumentNamesFromStringArray(argNames); } // 绑定参数 // 若是第一个参数类型是JoinPoint或procedure edingjoinpoint,那么将在那个位置传递一个JoinPoint (procedure edingjoinpoint for around advice)。 // 若是第一个参数是JoinPoint.StaticPart类型的,那么将会在对应位置绑定上一个JoinPoint.StaticPart参数。 // 剩下的参数必须由给定链接点上的切入点求值绑定,以此获得一个从参数名到值的映射。咱们须要计算须要将哪一个通知参数绑定到哪一个参数名。肯定这种绑定有多种策略,它们以责任链的形式排列。 springAdvice.calculateArgumentBindings(); return springAdvice; }
以建立建立OperationAop doBefore()方法的通知为例,传入的candidateAdviceMethod是切点方法。findAspectJAnnotationOnMethod(candidateAdviceMethod)获得的aspectJAnnotation对象结果以下:
annotation = "@org.aspectj.lang.annotation.Before(argNames=, value=doCut())" annotationType = "AtBefore" pointcutExpression = "doCut()" argumentNames = ""
而后根据下面不一样的分支建立不一样的Advice。springAdvice.calculateArgumentBindings();是进行参数绑定。(过程复杂,暂时没看)
到此,Spring AOP的元数据解析过程基本上算是分析完毕了。下一篇文章将着重介绍AOP类的建立过程,敬请期待!
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface HodayDouble { }
@Aspect @Component public class OperationAop { @Pointcut("@annotation(com.Hodey.analyseaop.anno.HodayDouble)") public void doCut(){} @Around("doCut()") public int doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { Object[] args = proceedingJoinPoint.getArgs(); int i = (int) args[0]; int j = (int) args[1]; System.out.println("入参:i:" + i); System.out.println("入参:j:" + j); System.out.println("before around"); int result = (int) proceedingJoinPoint.proceed(); System.out.println("after around"); System.out.println("原始结果:" + result); result = result * 2; System.out.println("代理结果:" + result); return result; } @Before("doCut()") public void doBefore(){ System.out.println("@Before print"); } @After("doCut()") public void doAfter(){ System.out.println("@After print"); } }
@Service("service") public class OperationService { @Autowired private OperationUtil ops; public int add(int i , int j){ return ops.add(i,j); } }
@Component public class OperationUtil { @HodayDouble public int add(int i, int j){ int result = i + j; return result; } }
@ComponentScan("com.Hodey") @EnableAutoConfiguration public class AnalyseAopApplication { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AnalyseAopApplication.class); OperationService opsService = (OperationService) ctx.getBean("service"); int result = opsService.add(2,3); System.out.println("最终结果:" + result); } }
执行结果:
入参:i:2 入参:j:3 before around @Before print after around 原始结果:5 代理结果:10 @After print 最终结果:10