Spring AOP 第二篇-Spring 如何解析切面获取切点,通知和生成代理对象

目录

Spring AOP 流程概述

AnnotationAwareAspectJAutoProxyCreator

AbstractAdvisorAutoProxyCreator

AbstractAutoProxyCreator

总结


Spring AOP 流程概述

        在上篇文章中,我们已经了解了 Spring AOP 到底是怎么使用的?此外我们还知道,要增强被代理对象,我们需要定义 Interceptor 或者Advice, 我们在使用 Spring AOP 的时候,虽然没有创建一个个拦截器,但是它底层代码会根据配置的注解,解析创建出一个拦截器出来,如标注了 @Before 注解的方法,就会创建出一个类型为 BeforeAdvice 类型的拦截器出来。然后会封装在 advisor 中。最终形成拦截器链,从而对被代理对象增强。 

        Spring AOP 流程

  1. 找到所有的切面 bean
  2. 遍历切面的方法,根据 @Before, @After 等注解生成对应的 Advisor
  3. 在创建 bean 的过程中,遍历 Advisor 数组,跟当前创建的 bean 进行匹配。
  4. 如果能匹配成功,说明当前对象需要被代理。根据被代理对象和 Advisor 数组来生成代理对象。

AnnotationAwareAspectJAutoProxyCreator

        上述 AOP 流程肯定是由专门处理 AOP 相关的模块来实现的。比如需要一些工具类才能辅助完成上面的操作。AnnotationAwareAspectJAutoProxyCreator 就是我们需要的那个工具类。

        首先看下类继承图

        可以发现它实现了 bean后置处理器的接口,意味着可以在bean创建出来之后,对这个 bean进行一些特殊操作。这么听起来是不是就很像对这个bean进行增强。

        首先看一下它的 findCandidateAdvisors() 方法

protected List<Advisor> findCandidateAdvisors() {
		// Add all the Spring advisors found according to superclass rules.
        //找到继承 Advisor 的 advisor
		List<Advisor> advisors = super.findCandidateAdvisors();
		// Build Advisors for all AspectJ aspects in the bean factory.
		if (this.aspectJAdvisorsBuilder != null) {
            //通过解析切面获取 advisor
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}

        首先可以分析下 super.findCandidateAdvisors(), 如果某个 Advisor 是通过继承了 Advisor 接口创建出来的,那么在这里就会找出来。下面 aspectJAdvisorsBuilder.buildAspectJAdvisors() 这个才是解析切面获取到的Advisor。        

//可以看到这个方法没有具体操作逻辑。而是调用了 advisorRetrievalHelper 的方法
protected List<Advisor> findCandidateAdvisors() {
		Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
		return this.advisorRetrievalHelper.findAdvisorBeans();
	}


public List<Advisor> findAdvisorBeans() {
		// Determine list of advisor bean names, if not cached already.
		String[] advisorNames = this.cachedAdvisorBeanNames;
		if (advisorNames == null) {
			// Do not initialize FactoryBeans here: We need to leave all regular beans
			// uninitialized to let the auto-proxy creator apply to them!
            //从这里可以看到。只获取 Advisor 类型的 bean 名称
			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)) {
					if (logger.isTraceEnabled()) {
						logger.trace("Skipping currently created advisor '" + name + "'");
					}
				}
				else {
					try {
                        //通过getBean方法获取 advisor 实例
						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)) {
								if (logger.isTraceEnabled()) {
									logger.trace("Skipping advisor '" + name +
											"' with dependency on currently created bean: " + ex.getMessage());
								}
								// Ignore: indicates a reference back to the bean we're trying to advise.
								// We want to find advisors other than the currently created bean itself.
								continue;
							}
						}
						throw ex;
					}
				}
			}
		}
		return advisors;
	}

        可以看到,获取继承自 Advisor 接口的实例 advisor 需要两步,第一步是获取到 Advisor 类型的bean名称。第二步是根据 bean 名称,调用getBean() 方法来获取 advisor 实例。不过这种 advisor 我们一般不会用,重要的是下面的这个方法

public List<Advisor> buildAspectJAdvisors() {
        //尝试获取缓存切面
		List<String> aspectNames = this.aspectBeanNames;

		if (aspectNames == null) {
			synchronized (this) {
				aspectNames = this.aspectBeanNames;
				if (aspectNames == null) {
					List<Advisor> advisors = new ArrayList<>();
					aspectNames = new ArrayList<>();
                    //这里是获取到所有 Object 类型的 beanNames
					String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
							this.beanFactory, Object.class, true, false);
					for (String beanName : beanNames) {
                        //判断bean是否有资格进行切面解析。默认所有bean都是符合条件的
						if (!isEligibleBean(beanName)) {
							continue;
						}
						// We must be careful not to instantiate beans eagerly as in this case they
						// would be cached by the Spring container but would not have been weaved.
						Class<?> beanType = this.beanFactory.getType(beanName);
						if (beanType == null) {
							continue;
						}
                        //判断是否为 Spring 类型的 @Aspect 切面。
						if (this.advisorFactory.isAspect(beanType)) {
							aspectNames.add(beanName);
							AspectMetadata amd = new AspectMetadata(beanType, beanName);
							if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                                //为单例 bean 实现增强的 Aspect 的逻辑
								MetadataAwareAspectInstanceFactory factory =
										new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                                //获取当前切面的所有 advisor
								List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                                // 将 advisor 放入缓存中。
								if (this.beanFactory.isSingleton(beanName)) {
									this.advisorsCache.put(beanName, classAdvisors);
								}
								else {
									this.aspectFactoryCache.put(beanName, factory);
								}
								advisors.addAll(classAdvisors);
							}
							else {
								// Per target or per this.
                                // 为多例 bean 增强的切面的处理逻辑
								if (this.beanFactory.isSingleton(beanName)) {
									throw new IllegalArgumentException("Bean with name '" + beanName +
											"' is a singleton, but aspect instantiation model is not singleton");
								}
								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) {
            //从缓存中获取到所有的 advisor
			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;
	}

        @Aspect() 可以指定 perthis, pertarget, 这是为多例 bean 提供增强的切面类型。它不会缓存advisor, 而是缓存了factory, 需要advisor 的时候,重新调用 getAdvisors() 再生成。而处理单例的切面类型会直接缓存advisor,这是二者不同的地方,不过到现在也可以发现,无论是哪种方式,this.advisorFactory.getAdvisors(factory) 都是至关重要的,需要靠它来获取到 advisor。

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
		Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
		validate(aspectClass);

		// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
		// so that it will only instantiate once.
		MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
				new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

		List<Advisor> advisors = new ArrayList<>();
        //遍历切面方法,这里会把标注了@Pointcut 注解的排除掉,只剩下通知注解,如@Before,@After
		for (Method method : getAdvisorMethods(aspectClass)) {
			// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
			// to getAdvisor(...) to represent the "current position" in the declared methods list.
			// However, since Java 7 the "current position" is not valid since the JDK no longer
			// returns declared methods in the order in which they are declared in the source code.
			// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
			// discovered via reflection in order to support reliable advice ordering across JVM launches.
			// Specifically, a value of 0 aligns with the default value used in
			// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
            //构造advisor
			Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

		// If it's a per target aspect, emit the dummy instantiating aspect.
		if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
			Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
			advisors.add(0, instantiationAdvisor);
		}

		// Find introduction fields.
		for (Field field : aspectClass.getDeclaredFields()) {
			Advisor advisor = getDeclareParentsAdvisor(field);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

		return advisors;
	}

       我们从代码可以看到,首先会遍历切面类的方法,即我们的通知,然后再根据通知去构造出我们需要的Advisor。也就是说一个通知会生成一个对应的 Advisor。我们知道,Advisor 最重要的就是它封装的通知(Advice)和切点(Pointcut)。我们进入getAdvisor方法探索一下它到底是如何构造的。        

//获取Advisor方法
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
			int declarationOrderInAspect, String aspectName) {
        //校验有效性
		validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
        //根据通知和切面类获取切点
		AspectJExpressionPointcut expressionPointcut = getPointcut(
				candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
		if (expressionPointcut == null) {
			return null;
		}
        
        //这里直接生成了一个 advisor 实例返回
		return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
				this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
	}

         上面我们可以看到首先实例化了 Pointcut, 然后就开始实例化 Advisor 了,那么我们可以猜测 Advice 是在实例化 Advisor 的时候实例化出来的。此时我们首先看一下实例化 Pointcut 的过程。

//获取切点实例方法
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
        // 获取了一个 AspectJAnnotation 的实例
		AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
		if (aspectJAnnotation == null) {
			return null;
		}
        //实例化切点
		AspectJExpressionPointcut ajexp =
				new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
		ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
		if (this.beanFactory != null) {
			ajexp.setBeanFactory(this.beanFactory);
		}
        //如此,切点就实例化好了,可以用它来匹配目标方法
		return ajexp;
	}

        这个方法主要有两步,第一步是获取了一个 AspectJAnnotation 的实例,第二步是实例化 Pointcut, 然后还通过第一步得到的 AspectJAnnotation 的实例获取到 Expression 信息,所以可以推测第一步获取到的实例是跟表达式相关的。我们探究一下

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;
	}


private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
			Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};

//可以看到上面遍历了切点注解类型的类数组信息,然后将当前方法和类信息作为参数调用 findAnnotation 方法。我们继续跟进

private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
        //这个方法很常见了,他就是获取类上面的注解信息
		A result = AnnotationUtils.findAnnotation(method, toLookFor);
		if (result != null) {
            //返回类注解信息的包装类实例
			return new AspectJAnnotation<>(result);
		}
		else {
			return null;
		}
	}

//包装类实例构造方法
public AspectJAnnotation(A annotation) {
            //注解属性赋值
			this.annotation = annotation;
            //获取注解类型并赋值
			this.annotationType = determineAnnotationType(annotation);
			try {
                //获取切点表达式并赋值
				this.pointcutExpression = resolveExpression(annotation);
				Object argNames = AnnotationUtils.getValue(annotation, "argNames");
				this.argumentNames = (argNames instanceof String ? (String) argNames : "");
			}
			catch (Exception ex) {
				throw new IllegalArgumentException(annotation + " is not a valid AspectJ annotation", ex);
			}
		}

//可以看到上面通过注解实例,获取到了注解类型和切点表达式,先看一下注解类型是什么
private AspectJAnnotationType determineAnnotationType(A annotation) {
			AspectJAnnotationType type = annotationTypeMap.get(annotation.annotationType());
			if (type != null) {
				return type;
			}
			throw new IllegalStateException("Unknown annotation type: " + annotation);
		}

//可以看到是从 annotationTypeMap 直接获取值返回,那么 annotationTypeMap 是什么呢?
private static Map<Class<?>, AspectJAnnotationType> annotationTypeMap = new HashMap<>(8);

		static {
			annotationTypeMap.put(Pointcut.class, AspectJAnnotationType.AtPointcut);
			annotationTypeMap.put(Around.class, AspectJAnnotationType.AtAround);
			annotationTypeMap.put(Before.class, AspectJAnnotationType.AtBefore);
			annotationTypeMap.put(After.class, AspectJAnnotationType.AtAfter);
			annotationTypeMap.put(AfterReturning.class, AspectJAnnotationType.AtAfterReturning);
			annotationTypeMap.put(AfterThrowing.class, AspectJAnnotationType.AtAfterThrowing);
		}

//可以看到他就是一个简单的映射,根据注解类型映射成对应的枚举类型,我们接下来看一下怎么解析的切点表达式


private String resolveExpression(A annotation) {
            //EXPRESSION_ATTRIBUTES 数组信息在下面,我们可以看到它就是获取注解的属性值信息,我们可以通过@Before(value="pointCut"),或者 @AfterReturning(pointcut = "pointCut()") 来配置切点表达式信息,那么在这里就可以获取到值,比如这个样例获取到的就是 “pointCut” 字符串
			for (String attributeName : EXPRESSION_ATTRIBUTES) {
				Object val = AnnotationUtils.getValue(annotation, attributeName);
				if (val instanceof String) {
					String str = (String) val;
					if (!str.isEmpty()) {
						return str;
					}
				}
			}
			throw new IllegalStateException("Failed to resolve expression: " + annotation);
		}

private static final String[] EXPRESSION_ATTRIBUTES = new String[] {"pointcut", "value"};

         通过上面解析,我们知道了 AspectJAnnotation 实例解析了切点的类型信息和表达式信息,我们接着看一下切点的实例化。

AspectJExpressionPointcut ajexp =
				new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
		ajexp.setExpression(aspectJAnnotation.getPointcutExpression());


public AspectJExpressionPointcut(Class<?> declarationScope, String[] paramNames, Class<?>[] paramTypes) {
        //切面类信息
		this.pointcutDeclarationScope = declarationScope;
		if (paramNames.length != paramTypes.length) {
			throw new IllegalStateException(
					"Number of pointcut parameter names must match number of pointcut parameter types");
		}
        //参数信息
		this.pointcutParameterNames = paramNames;
        //参数类型
		this.pointcutParameterTypes = paramTypes;
	}

         可以看到调用构造函数就是简单的赋值操作,切后两个还都是空信息,然后调用ajexp.setExpression 就设置了第一步获取到的切点表达式。此时切点的实例化就结束了,可是这还没完,我们都知道在进行切点匹配的时候,有类信息匹配还有方法匹配,那么目前我们实例化过程如此简单,切点实例里也没有很多信息,它到底是如何匹配的呢?首先我们看一下  AspectJExpressionPointcut 类继承图。

         由类继承信息可以看到,它不仅仅实现了 Pointcut 接口,它还实现了 ClassFilter 和 MethodMatcher 接口,所以说,这个 AspectJExpressionPointcut 可真了不得,它自己就有类信息匹配和方法匹配的能力。

        走进 AspectJExpressionPointcut 看下它的方法信息,果然是重写了 getClassFilter 和 getMethodMatcher 方法,如下所示,可以看到它就是直接返回的是 this,简直太强了!可是obtainPointcutExpression() 这方法又是什么呢?我们刚刚实例化的时候,只是获取了切点表达式信息,比如本例的话就是 pointCut,那么如果要匹配肯定是要获取到 execution 配置的信息的,所以可以猜测,这个方法就是来干这件事情的。

@Override
	public ClassFilter getClassFilter() {
		obtainPointcutExpression();
		return this;
	}

	@Override
	public MethodMatcher getMethodMatcher() {
		obtainPointcutExpression();
		return this;
	}
private PointcutExpression obtainPointcutExpression() {
		if (getExpression() == null) {
			throw new IllegalStateException("Must set property 'expression' before attempting to match");
		}
		if (this.pointcutExpression == null) {
            //获取类加载器
			this.pointcutClassLoader = determinePointcutClassLoader();
            //获取切点表达式信息
			this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
		}
		return this.pointcutExpression;
	}


private PointcutExpression buildPointcutExpression(@Nullable ClassLoader classLoader) {
		PointcutParser parser = initializePointcutParser(classLoader);
		PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
		for (int i = 0; i < pointcutParameters.length; i++) {
			pointcutParameters[i] = parser.createPointcutParameter(
					this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
		}
        //解析切点表达式信息
		return parser.parsePointcutExpression(replaceBooleanOperators(resolveExpression()),
				this.pointcutDeclarationScope, pointcutParameters);
	}



public PointcutExpression parsePointcutExpression(String expression, Class<?> inScope, PointcutParameter[] formalParameters)
			throws UnsupportedPointcutPrimitiveException, IllegalArgumentException {
		PointcutExpressionImpl pcExpr = null;
		try {
            //这里获取到的还是通知配置的value的值,如本例的pointCut()
			Pointcut pc = resolvePointcutExpression(expression, inScope, formalParameters);
            //这里才是根据pointCut() 获取到 execution 配置的信息
			pc = concretizePointcutExpression(pc, inScope, formalParameters);
			validateAgainstSupportedPrimitives(pc, expression); // again, because we have now followed any ref'd pcuts
			pcExpr = new PointcutExpressionImpl(pc, expression, formalParameters, getWorld());
		} catch (ParserException pEx) {
			throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx));
		} catch (ReflectionWorld.ReflectionWorldException rwEx) {
			throw new IllegalArgumentException(rwEx.getMessage());
		}
		return pcExpr;
	}

        通过pointCut 获取切点表达式的逻辑极其复杂,而且我觉得每一步的代码都列出来意义也不大,它无非就是找方法上面的注解,然后再找注解配置的值,就像我们解析 @Before 的 value 值一样。但是因为切点表达式可以配置多个,还有逻辑运算符 与,或,非。 所以解析过程相对复杂一些,我把几个重要的方法列出来,感兴趣的同学可以自己debug去跟一下。  

public Pointcut parseSinglePointcut() {
		int start = tokenSource.getIndex();
		IToken t = tokenSource.peek();
		Pointcut p = t.maybeGetParsedPointcut();
		if (p != null) {
			tokenSource.next();
			return p;
		}

		String kind = parseIdentifier();
		// IToken possibleTypeVariableToken = tokenSource.peek();
		// String[] typeVariables = maybeParseSimpleTypeVariableList();
		if (kind.equals("execution") || kind.equals("call") || kind.equals("get") || kind.equals("set")) {
			p = parseKindedPointcut(kind);
		} else if (kind.equals("args")) {
			p = parseArgsPointcut();
		} else if (kind.equals("this")) {
			p = parseThisOrTargetPointcut(kind);
		} else if (kind.equals("target")) {
			p = parseThisOrTargetPointcut(kind);
		} else if (kind.equals("within")) {
			p = parseWithinPointcut();
		} else if (kind.equals("withincode")) {
			p = parseWithinCodePointcut();
		} else if (kind.equals("cflow")) {
			p = parseCflowPointcut(false);
		} else if (kind.equals("cflowbelow")) {
			p = parseCflowPointcut(true);
		} else if (kind.equals("adviceexecution")) {
			eat("(");
			eat(")");
			p = new KindedPointcut(Shadow.AdviceExecution, new SignaturePattern(Member.ADVICE, ModifiersPattern.ANY,
					TypePattern.ANY, TypePattern.ANY, NamePattern.ANY, TypePatternList.ANY, ThrowsPattern.ANY,
					AnnotationTypePattern.ANY));
		} else if (kind.equals("handler")) {
			eat("(");
			TypePattern typePat = parseTypePattern(false, false);
			eat(")");
			p = new HandlerPointcut(typePat);
		} else if (kind.equals("lock") || kind.equals("unlock")) {
			p = parseMonitorPointcut(kind);
		} else if (kind.equals("initialization")) {
			eat("(");
			SignaturePattern sig = parseConstructorSignaturePattern();
			eat(")");
			p = new KindedPointcut(Shadow.Initialization, sig);
		} else if (kind.equals("staticinitialization")) {
			eat("(");
			TypePattern typePat = parseTypePattern(false, false);
			eat(")");
			p = new KindedPointcut(Shadow.StaticInitialization, new SignaturePattern(Member.STATIC_INITIALIZATION,
					ModifiersPattern.ANY, TypePattern.ANY, typePat, NamePattern.ANY, TypePatternList.EMPTY, ThrowsPattern.ANY,
					AnnotationTypePattern.ANY));
		} else if (kind.equals("preinitialization")) {
			eat("(");
			SignaturePattern sig = parseConstructorSignaturePattern();
			eat(")");
			p = new KindedPointcut(Shadow.PreInitialization, sig);
		} else if (kind.equals("if")) {
			// - annotation style only allows if(), if(true) or if(false)
			// - if() means the body of the annotated method represents the if expression
			// - anything else is an error because code cannot be put into the if()
			// - code style will already have been processed and the call to maybeGetParsedPointcut()
			// at the top of this method will have succeeded.
			eat("(");
			if (maybeEatIdentifier("true")) {
				eat(")");
				p = new IfPointcut.IfTruePointcut();
			} else if (maybeEatIdentifier("false")) {
				eat(")");
				p = new IfPointcut.IfFalsePointcut();
			} else {
				if (!maybeEat(")")) {
					throw new ParserException(
							"in annotation style, if(...) pointcuts cannot contain code. Use if() and put the code in the annotated method",
							t);
				}
				// TODO - Alex has some token stuff going on here to get a readable name in place of ""...
				p = new IfPointcut("");
			}
		} else {
			boolean matchedByExtensionDesignator = false;
			// see if a registered handler wants to parse it, otherwise
			// treat as a reference pointcut
			for (PointcutDesignatorHandler pcd : pointcutDesignatorHandlers) {
				if (pcd.getDesignatorName().equals(kind)) {
					p = parseDesignatorPointcut(pcd);
					matchedByExtensionDesignator = true;
				}

			}
			if (!matchedByExtensionDesignator) {
				tokenSource.setIndex(start);
				p = parseReferencePointcut();
			}
		}
		return p;
	}




private KindedPointcut parseKindedPointcut(String kind) {
		eat("(");
		SignaturePattern sig;

		Shadow.Kind shadowKind = null;
		if (kind.equals("execution")) {
			sig = parseMethodOrConstructorSignaturePattern();
			if (sig.getKind() == Member.METHOD) {
				shadowKind = Shadow.MethodExecution;
			} else if (sig.getKind() == Member.CONSTRUCTOR) {
				shadowKind = Shadow.ConstructorExecution;
			}
		} else if (kind.equals("call")) {
			sig = parseMethodOrConstructorSignaturePattern();
			if (sig.getKind() == Member.METHOD) {
				shadowKind = Shadow.MethodCall;
			} else if (sig.getKind() == Member.CONSTRUCTOR) {
				shadowKind = Shadow.ConstructorCall;
			}
		} else if (kind.equals("get")) {
			sig = parseFieldSignaturePattern();
			shadowKind = Shadow.FieldGet;
		} else if (kind.equals("set")) {
			sig = parseFieldSignaturePattern();
			shadowKind = Shadow.FieldSet;
		} else {
			throw new ParserException("bad kind: " + kind, tokenSource.peek());
		}
		eat(")");
		return new KindedPointcut(shadowKind, sig);
	}




public AnnotationTypePattern maybeParseSingleAnnotationPattern() {
		AnnotationTypePattern ret = null;
		Map<String, String> values = null;
		// LALR(2) - fix by making "!@" a single token
		int startIndex = tokenSource.getIndex();
		if (maybeEat("!")) {
			if (maybeEat("@")) {
				if (maybeEat("(")) {
					TypePattern p = parseTypePattern();
					ret = new NotAnnotationTypePattern(new WildAnnotationTypePattern(p));
					eat(")");
					return ret;
				} else {
					TypePattern p = parseSingleTypePattern();
					if (maybeEatAdjacent("(")) {
						values = parseAnnotationValues();
						eat(")");
						ret = new NotAnnotationTypePattern(new WildAnnotationTypePattern(p, values));
					} else {
						ret = new NotAnnotationTypePattern(new WildAnnotationTypePattern(p));
					}
					return ret;
				}
			} else {
				tokenSource.setIndex(startIndex); // not for us!
				return ret;
			}
		}
		if (maybeEat("@")) {
			if (maybeEat("(")) {
				TypePattern p = parseTypePattern();
				ret = new WildAnnotationTypePattern(p);
				eat(")");
				return ret;
			} else {
				int atPos = tokenSource.peek(-1).getStart();
				TypePattern p = parseSingleTypePattern();
				if (maybeEatAdjacent("(")) {
					values = parseAnnotationValues();
					eat(")");
					ret = new WildAnnotationTypePattern(p, values);
				} else {
					ret = new WildAnnotationTypePattern(p);
				}
				ret.start = atPos;
				return ret;
			}
		} else {
			tokenSource.setIndex(startIndex); // not for us!
			return ret;
		}
	}

        通过上述的分析我们知道,切点实例已经被创建出来了,但是创建出来的实例还不能立刻投入使用,在进行方法或者类匹配的时候,还需要解析表达式信息,然后才能跟类或者方法匹配校验。

        Pointcut 实例化好了,那么接下来就需要看下 Advice 和 Advisor 怎么实例化出来的了。

//实例化advisor的构造方法
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
			Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
        //上一步获取到的切点实例
		this.declaredPointcut = declaredPointcut;
		this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
		this.methodName = aspectJAdviceMethod.getName();
		this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
		this.aspectJAdviceMethod = aspectJAdviceMethod;
		this.aspectJAdvisorFactory = aspectJAdvisorFactory;
		this.aspectInstanceFactory = aspectInstanceFactory;
		this.declarationOrder = declarationOrder;
		this.aspectName = aspectName;

		if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
			// Static part of the pointcut is a lazy type.
			Pointcut preInstantiationPointcut = Pointcuts.union(
					aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

			// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
			// If it's not a dynamic pointcut, it may be optimized out
			// by the Spring AOP infrastructure after the first evaluation.
			this.pointcut = new PerTargetInstantiationModelPointcut(
					this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
			this.lazy = true;
		}
		else {
			// A singleton aspect.
			this.pointcut = this.declaredPointcut;
			this.lazy = false;
            //获取 advice 实例
			this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
		}
	}

//实例化获取 Advice
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
		Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
				this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
		return (advice != null ? advice : EMPTY_ADVICE);
	}

//根据 @After,@Before 等注解生成对应的 Advice
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

		Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		validate(candidateAspectClass);
        //获取通知方法上面的注解,同时通过映射设置类型,比如@Poingcut 的类型为AspectJAnnotationType.AtPointcut,@Before 的类型为 AspectJAnnotationType.AtBefore
		AspectJAnnotation<?> aspectJAnnotation =
				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
		if (aspectJAnnotation == null) {
			return null;
		}

		// If we get here, we know we have an AspectJ method.
		// Check that it's an AspectJ-annotated class
		if (!isAspect(candidateAspectClass)) {
			throw new AopConfigException("Advice must be declared inside an aspect type: " +
					"Offending method '" + candidateAdviceMethod + "' in class [" +
					candidateAspectClass.getName() + "]");
		}

		if (logger.isDebugEnabled()) {
			logger.debug("Found AspectJ method: " + candidateAdviceMethod);
		}

		AbstractAspectJAdvice springAdvice;
        //根据注解类型,实例化对应的 Advice 
		switch (aspectJAnnotation.getAnnotationType()) {
			case AtPointcut:
				if (logger.isDebugEnabled()) {
					logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
				}
				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);
		}

		// Now to configure the advice...
		springAdvice.setAspectName(aspectName);
		springAdvice.setDeclarationOrder(declarationOrder);
		String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
		if (argNames != null) {
			springAdvice.setArgumentNamesFromStringArray(argNames);
		}
		springAdvice.calculateArgumentBindings();

		return springAdvice;
	}

        上述代码量比较多,但是主线流程就是获取Advisor, 且在 Advisor 构造函数里实例化 Advice, 实例化 Advice 的时候,是根据通知方法上的注解来实例化对应类型的 Advice。至此,解析切面中的切点和通知的部分就结束了,也就完成了开篇讲的 Sping AOP 流程的前两步。

AbstractAdvisorAutoProxyCreator

        这是一个抽象类,也是 AnnotationAwareAspectJAutoProxyCreator 的父类,上一步已经把切面中的 advisor 解析出来了。当前这个类可以为 bean 找到匹配的 advisor,进行特定的增强。毕竟 advisor 那么多,哪个才是它的真命天子呢?

protected Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
        //找到跟当前 bean 匹配的 advisor
		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}


protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
        //首先找到所有的 advisor, 我们上一步已经解析过了,再次调用该方法就可以直接从缓存中获取
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
        //从所有 advisor 中,筛选出跟当前 bean 匹配的 advisor
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        //处理 aspectJ 的逻辑,暂时先不管这个
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

protected List<Advisor> findAdvisorsThatCanApply(
			List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
        //设置当前匹配过程中的bean, 类似于做标记
		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
		try {
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
            // 解除标记
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
	}

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new ArrayList<>();
		for (Advisor candidate : candidateAdvisors) {
            //引介增强的逻辑,不常用
			if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
				eligibleAdvisors.add(candidate);
			}
		}
		boolean hasIntroductions = !eligibleAdvisors.isEmpty();
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor) {
				// already processed
				continue;
			}
            //普通bean增强的匹配
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}


public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
        //引介增强的匹配
		if (advisor instanceof IntroductionAdvisor) {
			return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
		}
		else if (advisor instanceof PointcutAdvisor) {
            //PointcutAdvisor 类型的匹配,Spring AOP 生成的advisor,通过这种类型匹配
			PointcutAdvisor pca = (PointcutAdvisor) advisor;
			return canApply(pca.getPointcut(), targetClass, hasIntroductions);
		}
		else {
			// It doesn't have a pointcut so we assume it applies.
			return true;
		}
	}


public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
		Assert.notNull(pc, "Pointcut must not be null");
        //这里调用了我们上面讲的 getClassFilter() 方法,这个时候会解析到切点表达式进行匹配
		if (!pc.getClassFilter().matches(targetClass)) {
			return false;
		}
        //通过切点获取到方法匹配器,跟刚刚的 getClassFilter 差不多,丰富切点实例信息,然后用于方法匹配
		MethodMatcher methodMatcher = pc.getMethodMatcher();
		if (methodMatcher == MethodMatcher.TRUE) {
			// No need to iterate the methods if we're matching any method anyway...
			return true;
		}

		IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
		if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
			introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
		}

		Set<Class<?>> classes = new LinkedHashSet<>();
		if (!Proxy.isProxyClass(targetClass)) {
			classes.add(ClassUtils.getUserClass(targetClass));
		}
		classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

		for (Class<?> clazz : classes) {
			Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
            //通过反射拿到被代理对象的所有方法
			for (Method method : methods) {
                //通过切点的方法匹配器跟方法进行匹配,如果匹配成功,就返回true。表示当前的advisor是可以用来增强这个bean的
				if (introductionAwareMethodMatcher != null ?
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
						methodMatcher.matches(method, targetClass)) {
					return true;
				}
			}
		}

		return false;
	}

        通过上面的解析,我们也知道如何根据解析出来的一堆 advisor, 然后一个个跟bean匹配,找到需要增强的 bean。也就完成了开篇讲的 Spring AOP 流程的第三步。

AbstractAutoProxyCreator

        这是 AbstractAdvisorAutoProxyCreator 的父类,也就是 AnnotationAwareAspectJAutoProxyCreator 父类的父类,所以当实例化 AnnotationAwareAspectJAutoProxyCreator 的时候,自然也就具备了 AbstractAutoProxyCreator 的功能。

        前面的步骤介绍了怎么解析切面和匹配 bean,那么获取到被代理 bean 和 advisor 之后,剩下的自然是创建代理对象了。             

//这是一个后置处理器方法,在 bean 调用初始化方法之后会调用该方法,如果 bean 需要增强的话,在这里就会生成一个代理对象返回。
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
            //判断是否已经提前代理了
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                //如果bean需要增强的话,这个方法会生成代理对象
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
        // 从缓存中获取是否需要代理,如果不需要代理则直接返回原来的bean
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
        // 第一个条件是判断当前bean是否是一些不需要被代理的bean,比如它就是一个拦截器,或者是一个切面,那么不用进行匹配筛选,也知道它是不需要被代理增强的。
        // 判断当前bean是否需要跳过,即不用被代理
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
        //获取用来跟当前 bean 匹配的所有 advisor, 上面已经分析过这个流程了。
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
            //将是否需要代理放入缓存中
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
            //创建代理对象
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}
        //将是否需要代理放入缓存中
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}


//这个方法是创建动态代理的方法,它用了 ProxyFactory advisors 等,这个在动态代理那篇文章中已经详细想过了。如果想了解的话可以跳到那一篇文章中查看
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}
        
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
        //设置advisors
		proxyFactory.addAdvisors(advisors);
        //设置被代理对象
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
        //AbstractAdvisorAutoProxyCreator 的 advisorsPreFiltered()返回值固定为 true,表示既然都要给生成代理对象了,那么切点表达式和类信息一定是匹配的,这里设置好,后面在进行类匹配的时候,一看到这个标记就知道当前类是匹配的
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		return proxyFactory.getProxy(getProxyClassLoader());
	}

        至此,一个代理对象就被创建出来了,其中最后一部分由代理工厂创建代理对象的部分在Spring-动态代理和拦截器 这篇文章讲过了。有兴趣的可以跳到那里看一下。

总结

        本文讲解了 Spring AOP 进行增强的几个主要流程。包括切面的解析,被代理对象的匹配和生成代理对象等。但是这只是列举出了一个个点。下一篇文章将会讲各个点连接成一个面,讲解各个点都是在哪里调用的,怎么将这么多点连接起来。相关的实例什么时候被创建出来的。感谢阅读~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值