目录
Spring AOP 流程概述
AnnotationAwareAspectJAutoProxyCreator
AbstractAdvisorAutoProxyCreator
AbstractAutoProxyCreator
总结
在上篇文章中,我们已经了解了 Spring AOP 到底是怎么使用的?此外我们还知道,要增强被代理对象,我们需要定义 Interceptor 或者Advice, 我们在使用 Spring AOP 的时候,虽然没有创建一个个拦截器,但是它底层代码会根据配置的注解,解析创建出一个拦截器出来,如标注了 @Before 注解的方法,就会创建出一个类型为 BeforeAdvice 类型的拦截器出来。然后会封装在 advisor 中。最终形成拦截器链,从而对被代理对象增强。
Spring AOP 流程
上述 AOP 流程肯定是由专门处理 AOP 相关的模块来实现的。比如需要一些工具类才能辅助完成上面的操作。AnnotationAwareAspectJAutoProxyCreator 就是我们需要的那个工具类。
可以发现它实现了 bean后置处理器的接口,意味着可以在bean创建出来之后,对这个 bean进行一些特殊操作。这么听起来是不是就很像对这个bean进行增强。
首先看一下它的 findCandidateAdvisors() 方法
protected List findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
//找到继承 Advisor 的 advisor
List 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 findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
public List 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 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 buildAspectJAdvisors() {
//尝试获取缓存切面
List aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List 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 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 advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
//从缓存中获取到所有的 advisor
List 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 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 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) 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 AspectJAnnotation findAnnotation(Method method, Class 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, 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 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 流程的前两步。
这是一个抽象类,也是 AnnotationAwareAspectJAutoProxyCreator 的父类,上一步已经把切面中的 advisor 解析出来了。当前这个类可以为 bean 找到匹配的 advisor,进行特定的增强。毕竟 advisor 那么多,哪个才是它的真命天子呢?
protected Object[] getAdvicesAndAdvisorsForBean(
Class beanClass, String beanName, @Nullable TargetSource targetSource) {
//找到跟当前 bean 匹配的 advisor
List advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List findEligibleAdvisors(Class beanClass, String beanName) {
//首先找到所有的 advisor, 我们上一步已经解析过了,再次调用该方法就可以直接从缓存中获取
List candidateAdvisors = findCandidateAdvisors();
//从所有 advisor 中,筛选出跟当前 bean 匹配的 advisor
List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
//处理 aspectJ 的逻辑,暂时先不管这个
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
protected List findAdvisorsThatCanApply(
List candidateAdvisors, Class beanClass, String beanName) {
//设置当前匹配过程中的bean, 类似于做标记
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
// 解除标记
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
public static List findAdvisorsThatCanApply(List candidateAdvisors, Class clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List 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> 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 流程的第三步。
这是 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 进行增强的几个主要流程。包括切面的解析,被代理对象的匹配和生成代理对象等。但是这只是列举出了一个个点。下一篇文章将会讲各个点连接成一个面,讲解各个点都是在哪里调用的,怎么将这么多点连接起来。相关的实例什么时候被创建出来的。感谢阅读~