Spring源码深度解析(郝佳)-学习-源码解析-aop切面表达式解析(二)

我们在使用Spring AOP时,在切面类上配置一个注解,再配置一个表达式,就实现了类或者方法的切面,Spring 又是如何实现的呢?根据我对源码的理解,Spring 先通过ASM包访问类字节码表,得到类注解及方法注解,在每个bean的实例化过程中,获取所有配置了@Aspect注解的类,获取类中所有方法,如果方法中配置了如@Before, @Around, @After, @AfterReturning, @AfterThrowing, @Pointcut,等注解,解析注解上的表达式,根据表达式和当前要初始化类方法进行匹配,匹配正确,生成相应的代理方法或对象。这是切面实现的大概流程,但是整个过程太复杂,今天,我们只针对其中一个点进行分析,也就是如何解析切点表达式。如何从ASM中获取类和方法的注解,在前面的博客中己经分析过了,对于如何匹配,如何生成代理 ,以及生成代理之后,如何调用。在后面的博客中,再来详述。先看示例如下:

AspectJTest

@Aspect
@Configuration
public class AspectJTest {
    @Before("execution(* com.spring_101_200.test_111_120.test_117_excution.excution1.*.*(..))")
    public void beforeTest() {
        System.out.println("beforeTest");
    }
}

今天我们主要分析Spring 是如何解析 execution(* com.spring_101_200.test_111_120.test_117_excution.excution1..(…)) 表达式。

MyService.java

@Service
public class MyService {
    public void service() {
        System.out.println("serivce");
    }
}

spring_117_excution1.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">


    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    <context:component-scan base-package="com.spring_101_200.test_111_120.test_117_excution.excution1"></context:component-scan>


</beans>

测试:

public static void main(String[] args) {
    ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring_101_200/config_111_120/spring117_excution/spring_117_excution1.xml");
    MyService myService = ac.getBean(MyService.class);
    myService.service();
}

结果输出:

在这里插入图片描述

PointcutParser.java

protected Pointcut resolvePointcutExpression(String expression, Class inScope, PointcutParameter[] formalParameters) {
	try {
		//创建PatternParser解析类,并在构造函数中分词
		PatternParser parser = new PatternParser(expression);
		parser.setPointcutDesignatorHandlers(pointcutDesignators, world);
		Pointcut pc = parser.parsePointcut();
		validateAgainstSupportedPrimitives(pc, expression);
		IScope resolutionScope = buildResolutionScope((inScope == null ? Object.class : inScope), formalParameters);
		pc = pc.resolve(resolutionScope);
		return pc;
	} catch (ParserException pEx) {
		throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx));
	}
}

Spring 所有解析切点表达式方法都在PatternParser类中,在PatternParser的构造函数中,实现对表达式的分词。下面,我们来看看,Spring是如何分词的。

PatternParser.java

public PatternParser(String data) {
	//在makeTokenSource方法中实现分词,分词得到tokenSource数组
	this(BasicTokenSource.makeTokenSource(data, null));
}

BasicTokenSource.java

public static ITokenSource makeTokenSource(String input, ISourceContext context) {
	//将表达式转化为字符数组
	char[] chars = input.toCharArray();
	int i = 0;
	//创建存储分词的集合
	List tokens = new ArrayList();
	
	while (i < chars.length) {
		char ch = chars[i++];			
		switch(ch) {
			case ' ':
			case '\t':
			case '\n':
			case '\r':
				continue;//如果是空格, '\t','\n','\r' ,直接跳过
			case '*':
			case '(':
			case ')':
			case '+':
			case '[':
			case ']':
			case ',':
			case '!':
			case ':':
			case '@':
			case '<':
			case '>':
			case '=':
			case 	'?': 
				//如果是 *...,创建BasicToken对象,将字符转化成字符串,保存当前字符所在表达式的开始位置和结束位置
			    tokens.add(BasicToken.makeOperator(makeString(ch), i-1, i-1));
			    continue;
			case '.':
				//如果读取到 . ,那么再向后读取两个字符
				if ((i+2)<=chars.length) {
					char nextChar1 = chars[i];
					char nextChar2 = chars[i+1];
					//如果是'...' ,那么 ch==chars[i+1]==chars[i+2] == '.',保存字符串值为"..." 的BasicToken对象,并且
					// isIdentifier属性为true,同样保存字符串所在表达式的位置,并且字符数组下标向后移到两位
					if (ch==nextChar1 && ch==nextChar2) {
						tokens.add(BasicToken.makeIdentifier("...",i-1,i+1));
						i=i+2;
					} else {
						//保存字符串值为. 的BasicToken对象
						tokens.add(BasicToken.makeOperator(makeString(ch), i-1, i-1));
					}
				} else {
					//如果字符串的后缀是 .a ,i+2 > chars.length,因此进入下面的执行
					tokens.add(BasicToken.makeOperator(makeString(ch), i-1, i-1));
				}
				continue;
			case '&':
				if ((i+1) <= chars.length && chars[i] != '&') {
					//如果读取读取到字符是&,但后面的第一个字符不是&,直接保存为字符串值为&的BasicToken对象
					tokens.add(BasicToken.makeOperator(makeString(ch),i-1,i-1));
					continue;
				}
			case '|':
			    if (i == chars.length) {
			    	// 如果 & 或 |不是成对出现,将抛出异常
			    	throw new BCException("bad " + ch);
			    }
			    char nextChar = chars[i++];
			    if (nextChar == ch) {
			    	// 如果 & 或 | 成对出现,&& 或 || ,将保存字符串为 && 的BasicToken对象,否则,抛出异常
			    	tokens.add(BasicToken.makeOperator(makeString(ch, 2), i-2, i-1));
			    } else {
			    	throw new RuntimeException("bad " + ch);
			    }
			    continue;
			case '\"'://如果读取到" ,则截取""之间的值,保存为BasicToken对象
			    int start0 = i-1;
			    while (i < chars.length && !(chars[i]=='\"')) i++;
			    i += 1;
			    tokens.add(BasicToken.makeLiteral(new String(chars, start0+1, i-start0-2), "string", start0, i-1));
			    continue;
			default:
			    int start = i-1;
			    //否则,只要是java字符,将一直读取
			    while (i < chars.length && Character.isJavaIdentifierPart(chars[i])) { i++; }
			    tokens.add(BasicToken.makeIdentifier(new String(chars, start, i-start), start, i-1));
		}
	}
	return new BasicTokenSource((IToken[])tokens.toArray(new IToken[tokens.size()]), context);
}

其实,上面的这段分词的主要操作,去掉字符串之间的空格,Tab,回车,将字符串以 . [ ) { && || 分隔。
Token中有如下字段 :
         String value;
         boolean isIdentifier; //表示是一个字符串
         int start;
         int end;
例如:execution(* com.“spring_101_200”..(…) && xxx) ,分词得到
得到tokens :
[
        execution true 0:8,
        ‘(’ false 9:9,
        ‘’ false 10:10,
        com true 12:14,
        ‘.’ false 15:15,
        ‘spring_101_200’ false 16:31,
        ‘.’ false 32:32,
        '
’ false 33:33,
        ‘.’ false 34:34,
        ‘*’ false 35:35,
        ‘(’ false 36:36,
        ‘.’ false 37:37,
        ‘.’ false 38:38,
        ‘)’ false 39:39,
        ‘&&’ false 41:42,
        xxx true 44:46,
        ‘)’ false 47:47
]

接下来,我们来具体分析一下,如何得到Pointcut对象

PatternParser.java

public Pointcut parsePointcut() {
	Pointcut p = parseAtomicPointcut();
	if (maybeEat("&&")) {
		//如果 tokenSource 中还有未吃掉完的字符,且是&&,继续进行! 或者非&解析 
		p = new AndPointcut(p, parseNotOrPointcut());
	}

	if (maybeEat("||")) {
		//如果 tokenSource 中还有未吃掉完的字符,且是|| ,继续 pointCut 解析 
		p = new OrPointcut(p, parsePointcut());
	}

	return p;
}

private Pointcut parseAtomicPointcut() {
	if (maybeEat("!")) {
		//如果分词数组中当前解析元素是!,则进行 not  PointCut  相关解析
		int startPos = tokenSource.peek(-1).getStart();
		Pointcut p = new NotPointcut(parseAtomicPointcut(), startPos);
		return p;
	}
	if (maybeEat("(")) {
		//如果当前解析到的是括号,去掉括号
		Pointcut p = parsePointcut();
		eat(")");
		return p;
	}
	//如果当前解析到@,则进行注解相关解析
	if (maybeEat("@")) {
		int startPos = tokenSource.peek().getStart();
		Pointcut p = parseAnnotationPointcut();
		int endPos = tokenSource.peek(-1).getEnd();
		p.setLocation(sourceContext, startPos, endPos);
		return p;
	}
	int startPos = tokenSource.peek().getStart();
	//否则,进行单个 PointCut 解析
	Pointcut p = parseSinglePointcut();
	int endPos = tokenSource.peek(-1).getEnd();
	p.setLocation(sourceContext, startPos, endPos);
	return p;
}


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();
	if (kind.equals("execution") || kind.equals("call") || kind.equals("get") || kind.equals("set")) {
		//分词数组当前所在位置的字符串是,execution,call,get,set
		p = parseKindedPointcut(kind);
	} else if (kind.equals("args")) {
		//如:@Pointcut("args(java.io.Serializable,..)")
		p = parseArgsPointcut();
	} else if (kind.equals("this")) {
		//如:@Pointcut("this(com.spring_1_100.test_61_70.test64_2.UserService)")
		p = parseThisOrTargetPointcut(kind);
	} else if (kind.equals("target")) {
		//如:@Pointcut("target(com.spring_1_100.test_61_70.test64_2.UserService)")
		p = parseThisOrTargetPointcut(kind);
	} else if (kind.equals("within")) {
		//如:@Pointcut("within(com..test64_2..UserService+)")
		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;
	//如果分词数组所在位置的字符串是execution
	if (kind.equals("execution")) {
		//解析方法或者构造方法
		sig = parseMethodOrConstructorSignaturePattern();
		if (sig.getKind() == Member.METHOD) {
			//如果解析到的 PointCut 是方法,则设置shadowKind为Method
			shadowKind = Shadow.MethodExecution;
		} else if (sig.getKind() == Member.CONSTRUCTOR) {
			//如果解析到的 PointCut 是方法,则设置shadowKind为constructor Method
			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 SignaturePattern parseMethodOrConstructorSignaturePattern() {
	int startPos = tokenSource.peek().getStart();
	//也许解析注解表达式,如果解析不到,返回@ANY
	AnnotationTypePattern annotationPattern = maybeParseAnnotationPattern();
	//解析访问修饰符,比如 public ,private 等,比如 @Before("execution(public * *(..))")  中的 public     
	ModifiersPattern modifiers = parseModifiersPattern();
	//解析方法的返回值类型
	TypePattern returnType = parseTypePattern(false, false);
	//定义包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
	TypePattern declaringType;
	NamePattern name = null;
	MemberKind kind;
	//如果方法返回值参数之后是 new 修饰
	if (maybeEatNew(returnType)) {
		//当前kind是构造方法
		kind = Member.CONSTRUCTOR;
		if (returnType.toString().length() == 0) {
			declaringType = TypePattern.ANY;
		} else {
			declaringType = returnType;
		}
		returnType = TypePattern.ANY;
		name = NamePattern.ANY;
	} else {
		//当前kind是普通方法
		kind = Member.METHOD;
		IToken nameToken = tokenSource.peek();
		declaringType = parseTypePattern(false, false);
		if (maybeEat(".")) {
			nameToken = tokenSource.peek();
			name = parseNamePattern();
		} else {
			//获取具体的匹配的方法名称
			name = tryToExtractName(declaringType);
			//如果此时包名+类名为"",则匹配任意包
			if (declaringType.toString().equals("")) {
				declaringType = TypePattern.ANY;
			}
		}
		//如果匹配方法的具体名称为空,抛出异常
		if (name == null) {
			throw new ParserException("name pattern", tokenSource.peek());
		}
		//获取简单方法名
		String simpleName = name.maybeGetSimpleName();
		if (simpleName != null && simpleName.equals("new")) {
			throw new ParserException("method name (not constructor)", nameToken);
		}
	}
	//匹配方法参数
	TypePatternList parameterTypes = parseArgumentsPattern(true);
	//匹配方法抛出的异常类型
	ThrowsPattern throwsPattern = parseOptionalThrowsPattern();
	SignaturePattern ret = new SignaturePattern(kind, modifiers, returnType, declaringType, name, parameterTypes,
			throwsPattern, annotationPattern);
	int endPos = tokenSource.peek(-1).getEnd();
	ret.setLocation(sourceContext, startPos, endPos);
	return ret;
}

public ModifiersPattern parseModifiersPattern() {
	int requiredFlags = 0;
	int forbiddenFlags = 0;
	int start;
	while (true) {
		start = tokenSource.getIndex();
		boolean isForbidden = false;
		isForbidden = maybeEat("!");
		IToken t = tokenSource.next();
		//得到访问标识位的数值类型 如 :
		public  0x00000001 ,
		private 0x00000002 , 
		protected 0x00000004,
		static 0x00000008,
		final 0x00000010,
		这是 java字节码表就是这样规定的
		int flag = ModifiersPattern.getModifierFlag(t.getString());
		if (flag == -1) {
			break;
		}
		if (isForbidden) {
			forbiddenFlags |= flag;
		} else {
			//根据上面,我们知道如果一个类由 public final 修饰,那么得到的结果是0x00000011,十进制值为18
			requiredFlags |= flag;
		}
	}

	tokenSource.setIndex(start);
	if (requiredFlags == 0 && forbiddenFlags == 0) {
		return ModifiersPattern.ANY;
	} else {
		return new ModifiersPattern(requiredFlags, forbiddenFlags);
	}
}
public TypePattern parseTypePattern(boolean insideTypeParameters, boolean parameterAnnotationsPossible) {
	TypePattern p = parseAtomicTypePattern(insideTypeParameters, parameterAnnotationsPossible);
	if (maybeEat("&&")) {
		p = new AndTypePattern(p, parseNotOrTypePattern(insideTypeParameters, parameterAnnotationsPossible));
	}

	if (maybeEat("||")) {
		p = new OrTypePattern(p, parseTypePattern(insideTypeParameters, parameterAnnotationsPossible));
	}
	return p;
}
private TypePattern parseAtomicTypePattern(boolean insideTypeParameters, boolean parameterAnnotationsPossible) {
	//也许解析到注解类型
	AnnotationTypePattern ap = maybeParseAnnotationPattern();
	// 解析注解之后如果是!
	if (maybeEat("!")) {
		TypePattern p = null;
		TypePattern tp = parseAtomicTypePattern(insideTypeParameters, parameterAnnotationsPossible);
		if (!(ap instanceof AnyAnnotationTypePattern)) {
			//如果配置了注解,且又配置了tp类型,表示匹配的方法必需包含注解类型同时又不是 tp 类型
			p = new NotTypePattern(tp);
			p = new AndTypePattern(setAnnotationPatternForTypePattern(TypePattern.ANY, ap, false), p);
		} else {
			//匹配 ,非tp 类型
			p = new NotTypePattern(tp);
		}
		return p;
	}
	if (maybeEat("(")) {
		int openParenPos = tokenSource.peek(-1).getStart();
		TypePattern p = parseTypePattern(insideTypeParameters, false);
		if ((p instanceof NotTypePattern) && !(ap instanceof AnyAnnotationTypePattern)) {
			// @xxx(!com.test.AAA),表示不是 com.test.AAA类型,并配置了注解@xxx
			TypePattern tp = setAnnotationPatternForTypePattern(TypePattern.ANY, ap, parameterAnnotationsPossible);
			p = new AndTypePattern(tp, p);
		} else {
			// @xxx(com.test.AAA),表示是 com.test.AAA类型,并配置了注解@xxx
			p = setAnnotationPatternForTypePattern(p, ap, parameterAnnotationsPossible);
		}
		eat(")");
		int closeParenPos = tokenSource.peek(-1).getStart();
		//是否包含可变参数
		boolean isVarArgs = maybeEat("...");
		if (isVarArgs) {
			p.setIsVarArgs(isVarArgs);
		}
		boolean isIncludeSubtypes = maybeEat("+");
		if (isIncludeSubtypes) {
			p.includeSubtypes = true; // need the test because (A+) should not set subtypes to false!
		}
		p.start = openParenPos;
		p.end = closeParenPos;
		return p;
	}
	int startPos = tokenSource.peek().getStart();
	if (ap.start != -1) {
		startPos = ap.start;
	}
	TypePattern p = parseSingleTypePattern(insideTypeParameters);
	int endPos = tokenSource.peek(-1).getEnd();
	p = setAnnotationPatternForTypePattern(p, ap, false);
	p.setLocation(sourceContext, startPos, endPos);
	return p;
}
public TypePattern parseSingleTypePattern(boolean insideTypeParameters) {
	if (insideTypeParameters && maybeEat("?")) {
		return parseGenericsWildcardTypePattern();
	}
	if (allowHasTypePatterns) {
		if (maybeEatIdentifier("hasmethod")) {
			return parseHasMethodTypePattern();
		}
		if (maybeEatIdentifier("hasfield")) {
			return parseHasFieldTypePattern();
		}
	}

	// 如果参数中有 is 
	if (maybeEatIdentifier("is")) {
		int pos = tokenSource.getIndex() - 1;
		TypePattern typeIsPattern = parseIsTypePattern();
		if (typeIsPattern != null) {
			return typeIsPattern;
		}
		// rewind as if we never tried to parse it as a typeIs
		tokenSource.setIndex(pos);
	}
	// @Before("execution(* *(java.util.Map [][]<com..Model, com..Model>+[][]..., ..))")
	如果这样配置,下面的将全部被解析到
	List<NamePattern> names = parseDottedNamePattern();

	int dim = 0;
	while (maybeEat("[")) {
		eat("]");
		dim++;
	}

	TypePatternList typeParameters = maybeParseTypeParameterList();
	int endPos = tokenSource.peek(-1).getEnd();

	boolean includeSubtypes = maybeEat("+");

	// 主要是对数组级别的解析
	while (maybeEat("[")) {
		eat("]");
		dim++;
	}

	boolean isVarArgs = maybeEat("...");

	// 如果名字是* ,并且没有数组,没有可变参数,方法的参数还是空,则匹配任意类型
	if (names.size() == 1 && names.get(0).isAny() && dim == 0 && !isVarArgs && typeParameters == null) {
		return TypePattern.ANY;
	}

	// Notice we increase the dimensions if varargs is set. this is to allow type matching to
	// succeed later: The actual signature at runtime of a method declared varargs is an array type of
	// the original declared type (so Integer... becomes Integer[] in the bytecode). So, here for the
	// pattern 'Integer...' we create a WildTypePattern 'Integer[]' with varargs set. If this matches
	// during shadow matching, we confirm that the varargs flags match up before calling it a successful
	// match.
	return new WildTypePattern(names, includeSubtypes, dim + (isVarArgs ? 1 : 0), endPos, isVarArgs, typeParameters);
}
public AnnotationTypePattern maybeParseAnnotationPattern() {
	//默认,无论配置和不配置注解的方法都匹配
	AnnotationTypePattern ret = AnnotationTypePattern.ANY;
	AnnotationTypePattern nextPattern = null;
	//也许吃掉单个注解表达式
	while ((nextPattern = maybeParseSingleAnnotationPattern()) != null) {
		//如果只配置了单个注解,则直接返回单个注解
		if (ret == AnnotationTypePattern.ANY) {
			ret = nextPattern;
		} else {
			//如果配置了多个注解,则使用AndAnnotationTypePattern封装一下
			ret = new AndAnnotationTypePattern(ret, nextPattern);
		}
	}
	return ret;
}

public AnnotationTypePattern maybeParseSingleAnnotationPattern() {
	AnnotationTypePattern ret = null;
	Map<String, String> values = null;

	int startIndex = tokenSource.getIndex();
	if (maybeEat("!")) {
		//@Pointcut("execution(!@(java.lang.Deprecated || com.spring_1_100..MyAnnotation) * *(..))")
		//如果是以上配置先解析!,再解析@
		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("(")) {
			//如果是这样配置:@Pointcut("execution(@(java.lang.Deprecated || com.spring_1_100..MyAnnotation) * *(..))")
			TypePattern p = parseTypePattern();
			ret = new WildAnnotationTypePattern(p);
			eat(")");
			return ret;
		} else {
			//如果是这样配置 @Pointcut("execution(@java.lang.Deprecated @com.spring_1_100..MyAnnotation * *(..))")
			int atPos = tokenSource.peek(-1).getStart();
			TypePattern p = parseSingleTypePattern();
			if (maybeEatAdjacent("(")) {
				//如果注解中配置了属性,则解析出属性 map
				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;
	}
}


public TypePatternList parseArgumentsPattern(boolean parameterAnnotationsPossible) {
	List<TypePattern> patterns = new ArrayList<TypePattern>();
	//先吃掉方法的左括号
	eat("(");
	//再尝试吃掉方法的右括号,如果方法中没有配置参数,此时返回
	if (maybeEat(")")) {
		return new TypePatternList();
	}

	do {
		if (maybeEat(".")) { //如果方法里第一个元素是.,那么必然第二个元素也是.
			eat(".");
			//当前参数类型是省略类型,也就是可以是任意类型
			patterns.add(TypePattern.ELLIPSIS);
		} else {
			//再次递归查找方法参数类型
			patterns.add(parseTypePattern(false, parameterAnnotationsPossible));
		}
	} while (maybeEat(","));  //如果方法第一个参数解析完后,接,  则继续解析,否则跳出循环,方法参数解析结束
	eat(")");
	return new TypePatternList(patterns);
}


public ThrowsPattern parseOptionalThrowsPattern() {
	IToken t = tokenSource.peek();
	// 如果方法右括号之后的第一个元素是 throws 元素
	if (t.isIdentifier() && t.getString().equals("throws")) {
		tokenSource.next();
		//这里可以是排除方法抛出某类异常,也可是方法必需抛出某类异常,才做 PointCut 拦截 
		List<TypePattern> required = new ArrayList<TypePattern>();
		List<TypePattern> forbidden = new ArrayList<TypePattern>();
		do {
			//如果throws 后面是!,只要抛出该类异常的方法,将不做拦截
			boolean isForbidden = maybeEat("!");
			TypePattern p = parseTypePattern();
			if (isForbidden) {
				forbidden.add(p);
			} else {
				//否则,方法必需抛出throws 后所配置的异常,才进行拦截,如果配置多个异常,则需要方法同时抛出多个异常时,才进行方法的切面拦截。
				required.add(p);
			}
		} while (maybeEat(","));
		return new ThrowsPattern(new TypePatternList(required), new TypePatternList(forbidden));
	}
	//如果方法后没有配置 throws ,表示方法无论是抛出异常还是不抛出异常,都进行拦截
	return ThrowsPattern.ANY;
}


//表达式解析到这里,己经解析完成了,最终返回一个SignaturePattern对象。用于对 Spring 中所有 bean方法的过滤匹配
public SignaturePattern(MemberKind kind, ModifiersPattern modifiers, TypePattern returnType, TypePattern declaringType,
		NamePattern name, TypePatternList parameterTypes, ThrowsPattern throwsPattern, AnnotationTypePattern annotationPattern) {
	this.kind = kind;//方法是普通方法还是构造方法
	this.modifiers = modifiers;//方法修饰符限制
	this.returnType = returnType;//方法返回值类型限制
	this.name = name;//所匹配的方法名称限制
	this.declaringType = declaringType;//方法所在包+类名限制
	this.parameterTypes = parameterTypes;//方法参数类型限制
	this.throwsPattern = throwsPattern;//方法异常类型限制
	this.annotationPattern = annotationPattern;//方法注解类型限制
	this.isExactDeclaringTypePattern = (declaringType instanceof ExactTypePattern);
}

最终,我们根据表达式得到 PointCut 如下图所示

在这里插入图片描述
经过上面的分析,我相信,如果没有阅读过这一部分源码的小伙伴肯定很晕,不知道在说些什么,下面我们来总结一下

  1. Spring 先对表达式进行分词,去除空格,tab,回车,等。
  2. 解析execution()表达式主体。
  3. 解析是否配置了方法修饰符,如public ,private ,protected 等
  4. 解析返回类型,*号表示所有的类型。
  5. 解析需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
  6. 从包名中提取类名,如果是*号表示所有的类。
  7. 解析方法参数,*(…):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。
  8. 解析方法后是否配置了异常类,如果配置多个,则表示方法同时要抛出多个异常,才符合条件。

解析流程:

	1) PatternParser(expression)  :传入切面表达式进行分词;
		1)makeOperator(): 创建符号BasicToken;
		2)makeIdentifier(): 创建字符串BasicToken;
		3)makeLiteral(): 创建string类型的BasicToken;
	2)parsePointcut() : 解析 PointCut
		1)parseAtomicPointcut() :解析原子 PointCut
			1)new NotPointcut(parseAtomicPointcut(), startPos) :如果当前解析到的分词元素是!,则创建NotPointcut
			2)parsePointcut() : 如果当前是( ,则再次递归解析 PointCut 
			3) parseAnnotationPointcut() :如果当前是@ ,则解析注解 PointCut 
			4) parseSinglePointcut() :解析单个 PointCut 
				1) parseKindedPointcut () : 如果当前是execution,call,get,set
					1)parseMethodOrConstructorSignaturePattern(): 如果是execution,则调用该方法
						1)maybeParseAnnotationPattern():解析注解匹配
						2)parseModifiersPattern():解析方法修饰符匹配
						3)parseTypePattern():解析返回值匹配
						4)declaringTypePattern():解析得到包名和类名匹配
						5)parseArgumentsPattern():解析得到方法参数匹配
						6)parseOptionalThrowsPattern():解析方法后的异常匹配
						7)new SignaturePattern(kind, modifiers, returnType, declaringType, name, parameterTypes,
				throwsPattern, annotationPattern):封装对象,返回方法各项目参数匹配。
					2)parseMethodOrConstructorSignaturePattern(): 如果是 call,则调用该方法
						...
					3)parseFieldSignaturePattern():如果是 get,set 则调用该方法
						1)maybeParseAnnotationPattern():解析注解匹配
						2)parseModifiersPattern():解析方法修饰符匹配
						3)parseTypePattern():解析返回值匹配
						4)declaringTypePattern():解析得到包名和类名匹配,
						5)parseNamePattern() : 如果解析到.,则进行名称匹配。到这里直接返回方法参数各项匹配,无参数,和异常类型匹配
				2) parseArgsPointcut() :
					1)parseArgumentsPattern() :直接进行参数类型匹配,返回 new ArgsPointcut(arguments);
				3)parseThisOrTargetPointcut(): this 或者 target 匹配,返回new ThisOrTargetPointcut(kind.equals("this"), type);
						...
				4) parseWithinPointcut(): 对于 within 类型表达式的匹配,解析出()内类型,直接返回new WithinPointcut(type);
						...
				...
		2)AndPointcut() :  如果原子 PointCut 后还有&& ,则创建AndPointcut
			1)left : PointCut 值
			2)right : PointCut 匹配结果取 left 和 right 的并集。
		3)OrPointcut() : 如果原子 PointCut 后还在 || ,则创建OrPointcut
			1)left : PointCut 值
			2)right : PointCut 匹配结果,只要任意一个符合要求,则匹配成功。

大体的思路是这样子的,但是实际的解析考虑的情况比上面要复杂得多,在里面很多递归调用,最后才得到我们的PointCut表达式,而,Spring 就是根据表达式的匹配,轮询 bean 中所有的方法,看是否能够匹配,如果能够匹配,才生成相应的动态代理类,和代理方法,从而实现切面。这里只是对表达式的解析进行分析,而表达式的匹配更加复杂,那在下一篇博客中再来做说明了吧。

本文的github地址是
https://github.com/quyixiao/spring_tiny/tree/master/src/main/java/com/spring_101_200/test_111_120/test_117_excution/excution1

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值