Spring源码深度解析(郝佳)-学习-Spel源码解析(三)-Math

20 篇文章 1 订阅
18 篇文章 0 订阅

今天来讲讲对于Math函数的Spel分析

@Test
public void test2() {
    ExpressionParser parser = new SpelExpressionParser();
    String randomPhrase = parser.parseExpression(
            "random number is #{T(java.lang.Math).round(30d)}",
            new TemplateParserContext()).getValue(String.class);
    System.out.println(randomPhrase);
}

【结果输出】
random number is 30
为什么会输出这样的结果,我们来分析源码

TemplateAwareExpressionParser.java

@Override
public Expression parseExpression(String expressionString, ParserContext context)
		throws ParseException {
	if (context == null) {
		context = NON_TEMPLATE_PARSER_CONTEXT;
	}
	if (context.isTemplate()) {
		return parseTemplate(expressionString, context);
	}
	else {
		return doParseExpression(expressionString, context);
	}
}

在这个方法中,我们传入了TemplateParserContext这个类。我们来看看这个类

public class TemplateParserContext implements ParserContext {
	private final String expressionPrefix;
	private final String expressionSuffix;
	//指定模板前缀为#{ 和后缀 }
	public TemplateParserContext() {
		this("#{", "}");
	}

	public TemplateParserContext(String expressionPrefix, String expressionSuffix) {
		this.expressionPrefix = expressionPrefix;
		this.expressionSuffix = expressionSuffix;
	}
	
	@Override
	public final boolean isTemplate() {
		return true;
	}

	@Override
	public final String getExpressionPrefix() {
		return this.expressionPrefix;
	}

	@Override
	public final String getExpressionSuffix() {
		return this.expressionSuffix;
	}

}

TemplateAwareExpressionParser.java

private Expression parseTemplate(String expressionString, ParserContext context)
		throws ParseException {
	if (expressionString.length() == 0) {
		return new LiteralExpression("");
	}
	//解析字符串
	Expression[] expressions = parseExpressions(expressionString, context);
	if (expressions.length == 1) {
		return expressions[0];
	}
	else {
		return new CompositeStringExpression(expressionString, expressions);
	}
}

TemplateAwareExpressionParser.java

private Expression[] parseExpressions(String expressionString, ParserContext context)
		throws ParseException {
	List<Expression> expressions = new LinkedList<Expression>();
	//获取前缀 ${ 
	String prefix = context.getExpressionPrefix();
	//获取后缀 }  
	String suffix = context.getExpressionSuffix();
	int startIdx = 0;
	while (startIdx < expressionString.length()) {
		int prefixIndex = expressionString.indexOf(prefix, startIdx);
		if (prefixIndex >= startIdx) {
			// 如果前缀 #{ 不是出现在第一个字符位置 ,
			// 像 random number is #{T(java.lang.Math).round(30d)} 
			if (prefixIndex > startIdx) {
				//直接返回LiteralExpression对象 
				expressions.add(createLiteralExpression(context,
						expressionString.substring(startIdx, prefixIndex)));
			}
			//获取 ${ 后的第一个字符的index 
			int afterPrefixIndex = prefixIndex + prefix.length();
			//匹配到 ${ 相匹配后缀的 } index, 
			// 也就是说,找到了 ${  ,和 ${ 相匹配的 } index位置
			int suffixIndex = skipToCorrectEndSuffix(prefix, suffix,
					expressionString, afterPrefixIndex);

			if (suffixIndex == -1) {
				throw new ParseException(expressionString, prefixIndex,
						"No ending suffix '" + suffix
								+ "' for expression starting at character "
								+ prefixIndex + ": "
								+ expressionString.substring(prefixIndex));
			}
			//如果只配置了${ 没有配置后缀,则抛出异常
			if (suffixIndex == afterPrefixIndex) {
				throw new ParseException(expressionString, prefixIndex,
						"No expression defined within delimiter '" + prefix + suffix
								+ "' at character " + prefixIndex);
			}
			
			String expr = expressionString.substring(prefixIndex + prefix.length(),	suffixIndex);
			//本例子终于得到了字符串 T(java.lang.Math).round(30d)
			expr = expr.trim();
		
			if (expr.length() == 0) {
				throw new ParseException(expressionString, prefixIndex,
						"No expression defined within delimiter '" + prefix + suffix
								+ "' at character " + prefixIndex);
			}
			//继续调用doParseExpression方法
			expressions.add(doParseExpression(expr, context));
			startIdx = suffixIndex + suffix.length();
		}
		else {
			// no more ${expressions} found in string, add rest as static text
			expressions.add(createLiteralExpression(context,
					expressionString.substring(startIdx)));
			startIdx = expressionString.length();
		}
	}
	return expressions.toArray(new Expression[expressions.size()]);
}

在这里插入图片描述

TemplateAwareExpressionParser.java

private int skipToCorrectEndSuffix(String prefix, String suffix,
		String expressionString, int afterPrefixIndex) throws ParseException {
	//保留${ 前缀所在位置
	int pos = afterPrefixIndex;
	//被解析字符串长度
	int maxlen = expressionString.length();
	//看被解析的字符串中和前缀 ${ 相匹配的后缀存在不?如果不存在,则抛出异常
	int nextSuffix = expressionString.indexOf(suffix, afterPrefixIndex);
	if (nextSuffix == -1) {
		return -1; 
	}
	//建立堆栈结构,用户保存被解析的字符串 { ,[  ,( 等
	Stack<Bracket> stack = new Stack<Bracket>();
	while (pos < maxlen) {
		//如果栈中的数据为空,并且匹配到了后缀 } ,则退出while循环
		//只是本例中的后缀为} ,其实前缀后缀可以根据用户的喜好随便定义的
		// 如 : $aaaa 为前缀 bbbb为后缀,都是可以的,在Spring中都帮我们实现了
		if (isSuffixHere(expressionString, pos, suffix) && stack.isEmpty()) {
			break;
		}
		char ch = expressionString.charAt(pos);
		switch (ch) {
			case '{':
			case '[':
			case '(':
				//如果解析到的字符串是 { ,[ ,( 压栈
				stack.push(new Bracket(ch, pos));
				break;
			case '}':
			case ']':
			case ')':
				//如果解析到的字符串是 } ,] ,) 出栈,当前栈中没有元素,则抛出异常,说明 括号不对应
				if (stack.isEmpty()) {
					throw new ParseException(expressionString, pos, "Found closing '"
							+ ch + "' at position " + pos + " without an opening '"
							+ Bracket.theOpenBracketFor(ch) + "'");
				}
				Bracket p = stack.pop();
				// 出栈,并且判断当前栈中的元素是不是和当前元素相对应,不允许出下 [ )  或者 { ] ,括号不对等的情况 
				if (!p.compatibleWithCloseBracket(ch)) {
					throw new ParseException(expressionString, pos, "Found closing '"
							+ ch + "' at position " + pos
							+ " but most recent opening is '" + p.bracket
							+ "' at position " + p.pos);
				}
				break;
			case '\'':
			case '"':
				// 如果是双引号,看当前被解析的字符串中是不是还有双引号,如果有,将pos位置移动到下一个双引号位置,
				//如果没有双引号了,直接抛出异常 
				int endLiteral = expressionString.indexOf(ch, pos + 1);
				if (endLiteral == -1) {
					throw new ParseException(expressionString, pos,
							"Found non terminating string literal starting at position "
									+ pos);
				}
				pos = endLiteral;
				break;
		}
		pos++;
	}
		// 如果栈中元素不为空,抛出异常
	if (!stack.isEmpty()) {
		Bracket p = stack.pop();
		throw new ParseException(expressionString, p.pos, "Missing closing '"
				+ Bracket.theCloseBracketFor(p.bracket) + "' for '" + p.bracket
				+ "' at position " + p.pos);
	}
	if (!isSuffixHere(expressionString, pos, suffix)) {
		return -1;
	}
	return pos;
}

TemplateAwareExpressionParser.java

private boolean isSuffixHere(String expressionString, int pos, String suffix) {
	int suffixPosition = 0;
	// 例如当前解析到的字符是 random number is #{T(java.lang.Math).round(30d)} bbbbbbbbbb
	// 30后面的d ,而后缀是 } 因此,返回false,继续循环,而只有当前字符串定位在 }  ,才可能返回true 
	// 为什么要用pos++的操作呢?主要目的是为了解析,当后缀设置不是一个字符串时候,
	// $aaa xxxx bbb , 设置前缀为 $aaa  ,后缀为 bbb,需要解析表达式中的内容时,
	// 这个时候就需要后缀就需要pos ++ 来全匹配了 
	for (int i = 0; i < suffix.length() && pos < expressionString.length(); i++) {
		if (expressionString.charAt(pos++) != suffix.charAt(suffixPosition++)) {
			return false;
		}
	}
	if (suffixPosition != suffix.length()) {
		//目前想不到什么情况会进入到这里,如果有想到的,帮我留言一下吧,我来补充一下 
		return false;
	}
	return true;
}

通过上面的解析,我们终于又到了我们熟悉的SpelExpressionParser类doParseExpression方法了。

SpelExpressionParser.java

@Override
protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException {
	//如果在new SpelExpressionParser这个对象时没有传入,则使用默认的SpelParserConfiguration实例作为configuration传入参数 
	return new InternalSpelExpressionParser(this.configuration).doParseExpression(expressionString, context);
}

又来到了我们熟悉的分词,吃掉表达式,封装对象的环节

@Override
protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException {
	try {
		this.expressionString = expressionString;
		//表达式分词
		Tokenizer tokenizer = new Tokenizer(expressionString);
		tokenizer.process();
		this.tokenStream = tokenizer.getTokens();
		this.tokenStreamLength = this.tokenStream.size();
		this.tokenStreamPointer = 0;
		this.constructedNodes.clear();
		//将表达式解析成SpelNodeImpl对象,这个方法很重要
		SpelNodeImpl ast = eatExpression();
		if (moreTokens()) {
			throw new SpelParseException(peekToken().startPos, SpelMessage.MORE_INPUT, toString(nextToken()));
		}
		//解析出来的表达式统一封装返回
		return new SpelExpression(expressionString, ast, this.configuration);
	}
	catch (InternalParseException ex) {
		throw ex.getCause();
	}
}

在这里插入图片描述
我们继续来分词

Tokenizer.java

public void process() {
	//循环遍历字符数组
	while (this.pos < this.max) {
		char ch = this.toProcess[this.pos];
		//如果ch是字母
		if (isAlphabetic(ch)) {
			lexIdentifier();
		}
		else {
			switch (ch) {
				case '+':
					//如果字符是++
					if (isTwoCharToken(TokenKind.INC)) {
						pushPairToken(TokenKind.INC);
					}
					else {
						//如果字符是+
						pushCharToken(TokenKind.PLUS);
					}
					break;
				case '_': //如果字符是下划线
					lexIdentifier();
					break;
				case '-':
					//如果字符是--
					if (isTwoCharToken(TokenKind.DEC)) {
						pushPairToken(TokenKind.DEC);
					}
					else {
						//字符是 - 
						pushCharToken(TokenKind.MINUS);
					}
					break;
				case ':':
					//如果字符是分号 
					pushCharToken(TokenKind.COLON);
					break;
				case '.'://如果字符是点 
					pushCharToken(TokenKind.DOT);
					break;
				case ','://如果字符是逗号 
					pushCharToken(TokenKind.COMMA);
					break;
				case '*'://如果字符是乘 
					pushCharToken(TokenKind.STAR);
					break;
				case '/'://如果字符是除 
					pushCharToken(TokenKind.DIV);
					break;
				case '%'://如果字符是取余 
					pushCharToken(TokenKind.MOD);
					break;
				case '('://如果字符是左小括号 
					pushCharToken(TokenKind.LPAREN);
					break;
				case ')'://如果字符是右小括号 
					pushCharToken(TokenKind.RPAREN);
					break;
				case '['://如果字符是左中括号 
					pushCharToken(TokenKind.LSQUARE);
					break;
				case '#'://如果字符是井号 
					pushCharToken(TokenKind.HASH);
					break;
				case ']'://如果字符是右中括号 
					pushCharToken(TokenKind.RSQUARE);
					break;
				case '{'://如果字符是左大括号 
					pushCharToken(TokenKind.LCURLY);
					break;
				case '}'://如果字符是右大括号 
					pushCharToken(TokenKind.RCURLY);
					break;
				case '@'://如果字符是@符号
					pushCharToken(TokenKind.BEAN_REF);
					break;
				case '^':
					//如果字符是 ^[ 
					if (isTwoCharToken(TokenKind.SELECT_FIRST)) {
						pushPairToken(TokenKind.SELECT_FIRST);
					}
					else {
						//如果字符是 ^ 
						pushCharToken(TokenKind.POWER);
					}
					break;
				case '!':
					//如果字符是 != 
					if (isTwoCharToken(TokenKind.NE)) {
						pushPairToken(TokenKind.NE);
					}
					//如果字符是 ![ 
					else if (isTwoCharToken(TokenKind.PROJECT)) {
						pushPairToken(TokenKind.PROJECT);
					}
					else {
						//如果字符是 ! 
						pushCharToken(TokenKind.NOT);
					}
					break;
				case '=':
					//如果字符是 == 
					if (isTwoCharToken(TokenKind.EQ)) {
						pushPairToken(TokenKind.EQ);
					}
					else {
						//如果字符是 = 
						pushCharToken(TokenKind.ASSIGN);
					}
					break;
				case '&':
					//如果字符是& ,但是不是 && 抛出异常
					if (!isTwoCharToken(TokenKind.SYMBOLIC_AND)) {
						throw new InternalParseException(new SpelParseException(
								this.expressionString, this.pos, SpelMessage.MISSING_CHARACTER,
								"&"));
					}
					pushPairToken(TokenKind.SYMBOLIC_AND);
					break;
				case '|':
					//如果字符是 |  ,但是不是 || 抛出异常
					if (!isTwoCharToken(TokenKind.SYMBOLIC_OR)) {
						throw new InternalParseException(new SpelParseException(
								this.expressionString, this.pos, SpelMessage.MISSING_CHARACTER,
								"|"));
					}
					pushPairToken(TokenKind.SYMBOLIC_OR);
					break;
				case '?':
					//如果字符是 ?[
					if (isTwoCharToken(TokenKind.SELECT)) {
						pushPairToken(TokenKind.SELECT);
					}
					//如果字符是 ?:
					else if (isTwoCharToken(TokenKind.ELVIS)) {
						pushPairToken(TokenKind.ELVIS);
					}
					//如果字符是 ?.
					else if (isTwoCharToken(TokenKind.SAFE_NAVI)) {
						pushPairToken(TokenKind.SAFE_NAVI);
					}
					//如果字符是 ?
					else {
						pushCharToken(TokenKind.QMARK);
					}
					break;
				case '$':
					//如果字符是 $[
					if (isTwoCharToken(TokenKind.SELECT_LAST)) {
						pushPairToken(TokenKind.SELECT_LAST);
					}
					//如果字符是 $
					else {
						lexIdentifier();
					}
					break;
				case '>':
					//如果字符是 >= 
					if (isTwoCharToken(TokenKind.GE)) {
						pushPairToken(TokenKind.GE);
					}
					else {
						//如果字符是 > 
						pushCharToken(TokenKind.GT);
					}
					break;
				case '<':
					//如果字符是 <= 
					if (isTwoCharToken(TokenKind.LE)) {
						pushPairToken(TokenKind.LE);
					}
					else {
						//如果字符是 < 
						pushCharToken(TokenKind.LT);
					}
					break;
				case '0':
				case '1':
				case '2':
				case '3':
				case '4':
				case '5':
				case '6':
				case '7':
				case '8':
				case '9':
					// 数字处理
					lexNumericLiteral(ch == '0');
					break;
				case ' ':
				case '\t':
				case '\r':
				case '\n':
					// 空格,回车,tab 处理
					this.pos++;
					break;
				case '\'':
					//单引号处理 
					lexQuotedStringLiteral();
					break;
				case '"':
					//双引号处理 
					lexDoubleQuotedStringLiteral();
					break;
				case 0:
					//0 处理 
					this.pos++; // will take us to the end
					break;
				case '\\':// 单斜杠处理,抛出异常 
					throw new InternalParseException(
							new SpelParseException(this.expressionString, this.pos, SpelMessage.UNEXPECTED_ESCAPE_CHAR));
				default:
					throw new IllegalStateException("Cannot handle (" + Integer.valueOf(ch) + ") '" + ch + "'");
			}
		}
	}
}

分词的第一个字符是T ,则进入lexIdentifier方法。
我们再来看看,我们要解析的表达式
T(java.lang.Math).round(30d)
1.因为’T’后面是 ( ,因此得到枚举类型是TokenKind.IDENTIFIER的Token对象。
(对应的是TokenKing.LPAREN
在这里插入图片描述
( 后面的java和下面的lang以及Math以及round都是一样的对应IDENTIFIER

. 对应的是TokenKind 为点的Token
在这里插入图片描述

在这里插入图片描述
右括号对应的是 TokenKind.RPAREN 的枚举类型,如图所示
在这里插入图片描述
下面是关于对应数字的分词,数字30d是如何实现的呢?

private void lexNumericLiteral(boolean firstCharIsZero) {
	boolean isReal = false;
	int start = this.pos;
	char ch = this.toProcess[this.pos + 1];
	boolean isHex = ch == 'x' || ch == 'X';

	//十六进制处理
	if (firstCharIsZero && isHex) {
		this.pos = this.pos + 1;
		do {
			this.pos++;
		}
		while (isHexadecimalDigit(this.toProcess[this.pos]));
		if (isChar('L', 'l')) {
			pushHexIntToken(subarray(start + 2, this.pos), true, start, this.pos);
			this.pos++;
		}
		else {
			pushHexIntToken(subarray(start + 2, this.pos), false, start, this.pos);
		}
		return;
	}
	//获取到所有的数字 
	do {
		this.pos++;
	}
	while (isDigit(this.toProcess[this.pos]));

	//如果数字后面的第一个字符是点 
	ch = this.toProcess[this.pos];
	if (ch == '.') {
		isReal = true;
		int dotpos = this.pos;
		do {
			this.pos++;
		}
		while (isDigit(this.toProcess[this.pos]));
		if (this.pos == dotpos + 1) {
			// the number is something like '3.'. It is really an int but may be
			// part of something like '3.toString()'. In this case process it as
			// an int and leave the dot as a separate token.
			this.pos = dotpos;
			pushIntToken(subarray(start, this.pos), false, start, this.pos);
			return;
		}
	}

	int endOfNumber = this.pos;

	// Now there may or may not be an exponent

	//如果数字后面是 L 或者 l ,表示的是Long类型
	if (isChar('L', 'l')) {
		if (isReal) { // 3.4L - not allowed
			throw new InternalParseException(new SpelParseException(this.expressionString,
					start, SpelMessage.REAL_CANNOT_BE_LONG));
		}
		pushIntToken(subarray(start, endOfNumber), true, start, endOfNumber);
		this.pos++;
	}
	//如果数字后面是E 或者 e 表示科学记数法
	else if (isExponentChar(this.toProcess[this.pos])) {
		isReal = true; // if it wasn't before, it is now
		this.pos++;
		char possibleSign = this.toProcess[this.pos];
		if (isSign(possibleSign)) {
			this.pos++;
		}

		// exponent digits
		do {
			this.pos++;
		}
		while (isDigit(this.toProcess[this.pos]));
		boolean isFloat = false;
		if (isFloatSuffix(this.toProcess[this.pos])) {
			isFloat = true;
			endOfNumber = ++this.pos;
		}
		else if (isDoubleSuffix(this.toProcess[this.pos])) {
			endOfNumber = ++this.pos;
		}
		pushRealToken(subarray(start, this.pos), isFloat, start, this.pos);
	}
	else {
		ch = this.toProcess[this.pos];
		boolean isFloat = false;
		//是符点类型
		if (isFloatSuffix(ch)) {
			isReal = true;
			isFloat = true;
			endOfNumber = ++this.pos;
		}
		//是Double类型
		else if (isDoubleSuffix(ch)) {
			isReal = true;
			endOfNumber = ++this.pos;
		}
		if (isReal) {
			//保存为符点类型的Token
			pushRealToken(subarray(start, endOfNumber), isFloat, start, endOfNumber);
		}
		else {
			pushIntToken(subarray(start, endOfNumber), false, start, endOfNumber);
		}
	}
}
private void pushRealToken(char[] data, boolean isFloat, int start, int end) {
	if (isFloat) {
		//真符点类型
		this.tokens.add(new Token(TokenKind.LITERAL_REAL_FLOAT, data, start, end));
	}
	else {
		//类 符点 
		this.tokens.add(new Token(TokenKind.LITERAL_REAL, data, start, end));
	}
}

到这里我们终于完成了分词,来看看分词结果
在这里插入图片描述
最终,我们得到了分词数组tokens 。
通过分词器,我们得到了一个Token集合。我们再来看看eatExpression方法,从语义上看这个方法是【吃掉表达式】的意思,那是如何吃掉表达式的呢?在进入方法之前,我们来了解一下吃掉表达式中几个常用方法。

InternalSpelExpressionParser.java

moreTokens

private boolean moreTokens() {
	return this.tokenStreamPointer<this.tokenStream.size();
}

this.tokenStreamPointer表示当前Token集合下标
this.tokenStream.size() 表示当前Token集合长度。
因为在吃掉表达式的方法中,每解析掉一个或者多个Token时候,集合下标增加。当moreTokens返回false时,解析结束。

peekToken

private Token peekToken() {
	if (this.tokenStreamPointer >= this.tokenStreamLength) {
		return null;
	}
	return this.tokenStream.get(this.tokenStreamPointer);
}

不难看出,返回当前下标对应的Token

带参数peekToken

private boolean peekToken(TokenKind possible1,TokenKind possible2) {
	if (!moreTokens()) {
		return false;
	}
	Token t = peekToken();
	return (t.kind == possible1 || t.kind == possible2);
}

当前Token的类型是不是传入的类型,如果当前Token是+ ,传入的类型也是+ ,返回true 。否则,false。

nextToken

private Token nextToken() {
	if (this.tokenStreamPointer >= this.tokenStreamLength) {
		return null;
	}
	return this.tokenStream.get(this.tokenStreamPointer++);
}

从这个方法中不难看出,nextToken 主要目标是返回当前下标的Token,并且让下标+1 ,那么下次再调用peekToken()方法或者nextToken()方法时,将返回当前下标对应的Token的下一个Token。

push

private final Stack constructedNodes = new Stack();

private void push(SpelNodeImpl newNode) {
	this.constructedNodes.push(newNode);
}

pop

private SpelNodeImpl pop() {
	return this.constructedNodes.pop();
}

constructedNodes这是一个栈结构,push方法每次向里面存数据。pop方法每次从栈中弹出数据。

我们了解了上面几个方法后,我们来分析代码

InternalSpelExpressionParser.java

private SpelNodeImpl eatExpression() {
	SpelNodeImpl expr = eatLogicalOrExpression();
	if (moreTokens()) {
		Token t = peekToken();
		if (t.kind == TokenKind.ASSIGN) {  // a=b
			if (expr == null) {
				expr = new NullLiteral(toPos(t.startPos - 1, t.endPos - 1));
			}
			nextToken();
			SpelNodeImpl assignedValue = eatLogicalOrExpression();
			return new Assign(toPos(t), expr, assignedValue);
		}

		if (t.kind == TokenKind.ELVIS) {  // a?:b (a if it isn't null, otherwise b)
			if (expr == null) {
				expr = new NullLiteral(toPos(t.startPos - 1, t.endPos - 2));
			}
			nextToken();  // elvis has left the building
			SpelNodeImpl valueIfNull = eatExpression();
			if (valueIfNull==null) {
				valueIfNull = new NullLiteral(toPos(t.startPos + 1, t.endPos + 1));
			}
			return new Elvis(toPos(t), expr, valueIfNull);
		}

		if (t.kind == TokenKind.QMARK) {  // a?b:c
			if (expr == null) {
				expr = new NullLiteral(toPos(t.startPos - 1, t.endPos - 1));
			}
			nextToken();
			SpelNodeImpl ifTrueExprValue = eatExpression();
			eatToken(TokenKind.COLON);
			SpelNodeImpl ifFalseExprValue = eatExpression();
			return new Ternary(toPos(t), expr, ifTrueExprValue, ifFalseExprValue);
		}
	}
	return expr;
}
//吃掉 OR 或者 || 
private SpelNodeImpl eatLogicalOrExpression() {
	SpelNodeImpl expr = eatLogicalAndExpression();
	while (peekIdentifierToken("or") || peekToken(TokenKind.SYMBOLIC_OR)) {
		Token t = nextToken();  //consume OR
		SpelNodeImpl rhExpr =eatLogicalAndExpression();
		checkOperands(t, expr, rhExpr);
		expr = new OpOr(toPos(t), expr, rhExpr);
	}
	return expr;
}
//吃掉 and 或者 && 
private SpelNodeImpl eatLogicalAndExpression() {
	SpelNodeImpl expr = eatRelationalExpression();
	while (peekIdentifierToken("and") || peekToken(TokenKind.SYMBOLIC_AND)) {
		Token t = nextToken();  // consume 'AND'
		SpelNodeImpl rhExpr = eatRelationalExpression();
		checkOperands(t, expr, rhExpr);
		expr = new OpAnd(toPos(t), expr, rhExpr);
	}
	return expr;
}

//吃掉 > ,< ,>= ,<=, == 等关系表达式 
private SpelNodeImpl eatRelationalExpression() {
	SpelNodeImpl expr = eatSumExpression();
	Token relationalOperatorToken = maybeEatRelationalOperator();
	if (relationalOperatorToken != null) {
		Token t = nextToken();  // consume relational operator token
		SpelNodeImpl rhExpr = eatSumExpression();
		checkOperands(t, expr, rhExpr);
		TokenKind tk = relationalOperatorToken.kind;

		if (relationalOperatorToken.isNumericRelationalOperator()) {
			int pos = toPos(t);
			if (tk == TokenKind.GT) {
				return new OpGT(pos, expr, rhExpr);
			}
			if (tk == TokenKind.LT) {
				return new OpLT(pos, expr, rhExpr);
			}
			if (tk == TokenKind.LE) {
				return new OpLE(pos, expr, rhExpr);
			}
			if (tk == TokenKind.GE) {
				return new OpGE(pos, expr, rhExpr);
			}
			if (tk == TokenKind.EQ) {
				return new OpEQ(pos, expr, rhExpr);
			}
			Assert.isTrue(tk == TokenKind.NE);
			return new OpNE(pos, expr, rhExpr);
		}

		if (tk == TokenKind.INSTANCEOF) {
			return new OperatorInstanceof(toPos(t), expr, rhExpr);
		}

		if (tk == TokenKind.MATCHES) {
			return new OperatorMatches(toPos(t), expr, rhExpr);
		}

		Assert.isTrue(tk == TokenKind.BETWEEN);
		return new OperatorBetween(toPos(t), expr, rhExpr);
	}
	return expr;
}
//吃掉 * , / , % 表达式  
private SpelNodeImpl eatSumExpression() {
	SpelNodeImpl expr = eatProductExpression();
	while (peekToken(TokenKind.PLUS, TokenKind.MINUS, TokenKind.INC)) {
		Token t = nextToken();//consume PLUS or MINUS or INC
		SpelNodeImpl rhExpr = eatProductExpression();
		checkRightOperand(t,rhExpr);
		if (t.kind == TokenKind.PLUS) {
			expr = new OpPlus(toPos(t), expr, rhExpr);
		}
		else if (t.kind == TokenKind.MINUS) {
			expr = new OpMinus(toPos(t), expr, rhExpr);
		}
	}
	return expr;
}
//吃掉  ^  
private SpelNodeImpl eatPowerIncDecExpression() {
	SpelNodeImpl expr = eatUnaryExpression();
	if (peekToken(TokenKind.POWER)) {
		Token t = nextToken();  //consume POWER
		SpelNodeImpl rhExpr = eatUnaryExpression();
		checkRightOperand(t,rhExpr);
		return new OperatorPower(toPos(t), expr, rhExpr);
	}

	if (expr != null && peekToken(TokenKind.INC,TokenKind.DEC)) {
		Token t = nextToken();  //consume INC/DEC
		if (t.getKind() == TokenKind.INC) {
			return new OpInc(toPos(t), true, expr);
		}
		return new OpDec(toPos(t), true, expr);
	}

	return expr;
}


//吃掉  + ,- ,! ,++,-- 表达式 
private SpelNodeImpl eatUnaryExpression() {
	if (peekToken(TokenKind.PLUS, TokenKind.MINUS, TokenKind.NOT)) {
		Token t = nextToken();
		SpelNodeImpl expr = eatUnaryExpression();
		if (t.kind == TokenKind.NOT) {
			return new OperatorNot(toPos(t), expr);
		}

		if (t.kind == TokenKind.PLUS) {
			return new OpPlus(toPos(t), expr);
		}
		Assert.isTrue(t.kind == TokenKind.MINUS);
		return new OpMinus(toPos(t), expr);

	}
	if (peekToken(TokenKind.INC, TokenKind.DEC)) {
		Token t = nextToken();
		SpelNodeImpl expr = eatUnaryExpression();
		if (t.getKind() == TokenKind.INC) {
			return new OpInc(toPos(t), false, expr);
		}
		return new OpDec(toPos(t), false, expr);
	}
	//如果以上都不是,那么只能吃掉主表达式了
	return eatPrimaryExpression();
}

private SpelNodeImpl eatPrimaryExpression() {
	List nodes = new ArrayList();
	SpelNodeImpl start = eatStartNode();  // always a start node
	nodes.add(start);
	//也许吃掉的Token,但不一定能吃得下
	while (maybeEatNode()) {
		nodes.add(pop());
	}
	if (nodes.size() == 1) {
		return nodes.get(0);
	}
	//复杂表达式
	return new CompoundExpression(toPos(start.getStartPosition(),
			nodes.get(nodes.size() - 1).getEndPosition()),
			nodes.toArray(new SpelNodeImpl[nodes.size()]));
}
private SpelNodeImpl eatStartNode() {
	if (maybeEatLiteral()) {	// tokens[0] 是 ( ,返回false 
		return pop();
	}
	else if (maybeEatParenExpression()) {// tokens[0] 是 ( ,则进行处理 
		return pop();
	}
	else if (maybeEatTypeReference() || maybeEatNullReference() || maybeEatConstructorReference() ||
			maybeEatMethodOrProperty(false) || maybeEatFunctionOrVar()) {
		return pop();
	}
	else if (maybeEatBeanReference()) {
		return pop();
	}
	else if (maybeEatProjection(false) || maybeEatSelection(false) || maybeEatIndexer()) {
		return pop();
	}
	else if (maybeEatInlineListOrMap()) {
		return pop();
	}
	else {
		return null;
	}
}

private boolean maybeEatLiteral() {
	Token t = peekToken();
	//如果token为空,直接返回false
	if (t == null) {
		return false;
	}
	//如果是int
	if (t.kind == TokenKind.LITERAL_INT) {
		push(Literal.getIntLiteral(t.data, toPos(t), 10));
	}
	//如果是long
	else if (t.kind == TokenKind.LITERAL_LONG) {
		push(Literal.getLongLiteral(t.data, toPos(t), 10));
	}
	else if (t.kind == TokenKind.LITERAL_HEXINT) {
		push(Literal.getIntLiteral(t.data, toPos(t), 16));
	}
	//如果是十六进制长整形
	else if (t.kind == TokenKind.LITERAL_HEXLONG) {
		push(Literal.getLongLiteral(t.data, toPos(t), 16));
	}
	else if (t.kind == TokenKind.LITERAL_REAL) {
		push(Literal.getRealLiteral(t.data, toPos(t), false));
	}
	else if (t.kind == TokenKind.LITERAL_REAL_FLOAT) {
		push(Literal.getRealLiteral(t.data, toPos(t), true));
	}
	else if (peekIdentifierToken("true")) {
		push(new BooleanLiteral(t.data, toPos(t), true));
	}
	else if (peekIdentifierToken("false")) {
		push(new BooleanLiteral(t.data, toPos(t), false));
	}
	else if (t.kind == TokenKind.LITERAL_STRING) {
		push(new StringLiteral(t.data, toPos(t), t.data));
	}
	else {
		return false;
	}
	nextToken();
	return true;
}

经过一波一波的查找,那我们到了解析T Token的方法

private boolean maybeEatTypeReference() {
	if (peekToken(TokenKind.IDENTIFIER)) {
		Token typeName = peekToken();
		//如果类型为 T 
		if (!typeName.stringValue().equals("T")) {
			return false;
		}
		//获取T后面的下一个Token
		Token t = nextToken();
		//如果是 ] ,表示的是一个 map 类型
		if (peekToken(TokenKind.RSQUARE)) {
			// looks like 'T]' (T is map key)
			push(new PropertyOrFieldReference(false,t.data,toPos(t)));
			return true;
		}
		//吃掉右括号,Spring Spel语法就是这样的
		eatToken(TokenKind.LPAREN);
		//
		SpelNodeImpl node = eatPossiblyQualifiedId();
		// dotted qualified id
		// Are there array dimensions?
		int dims = 0;
		while (peekToken(TokenKind.LSQUARE, true)) {
			eatToken(TokenKind.RSQUARE);
			dims++;
		}
		eatToken(TokenKind.RPAREN);
		//建成TypeReference返回
		this.constructedNodes.push(new TypeReference(toPos(typeName),node,dims));
		return true;
	}
	return false;
}
private SpelNodeImpl eatPossiblyQualifiedId() {
	LinkedList qualifiedIdPieces = new LinkedList();
	Token node = peekToken();
	//如果结点的类型是 TokenKind.DOT  或者 TokenKind.IDENTIFIER
	while (isValidQualifiedId(node)) {
		nextToken();
		//节点如果不是点 则以Identifier对象加入到qualifiedIdPieces中
		if (node.kind != TokenKind.DOT) {
			qualifiedIdPieces.add(new Identifier(node.stringValue(),toPos(node)));
		}
		//否则继续循环
		node = peekToken();
	}
	
	if (qualifiedIdPieces.isEmpty()) {
		if (node == null) {
			raiseInternalException( this.expressionString.length(), SpelMessage.OOD);
		}
		raiseInternalException(node.startPos, SpelMessage.NOT_EXPECTED_TOKEN,
				"qualified ID", node.getKind().toString().toLowerCase());
	}
	int pos = toPos(qualifiedIdPieces.getFirst().getStartPosition(), qualifiedIdPieces.getLast().getEndPosition());
	//T之后的括号里分词值保存为QualifiedIdentifier返回
	return new QualifiedIdentifier(pos, qualifiedIdPieces.toArray(new SpelNodeImpl[qualifiedIdPieces.size()]));
}

最后构建成TypeReference返回

//因为括号后面是点,因此进入括号后面的点表达式
private SpelNodeImpl eatDottedNode() {
	Token t = nextToken();// it was a '.' or a '?.'
	boolean nullSafeNavigation = t.kind == TokenKind.SAFE_NAVI;
	if (maybeEatMethodOrProperty(nullSafeNavigation) || maybeEatFunctionOrVar()
			|| maybeEatProjection(nullSafeNavigation)
			|| maybeEatSelection(nullSafeNavigation)) {
		return pop();
	}
	if (peekToken() == null) {
		// unexpectedly ran out of data
		raiseInternalException(t.startPos, SpelMessage.OOD);
	}
	else {
		raiseInternalException(t.startPos, SpelMessage.UNEXPECTED_DATA_AFTER_DOT,
				toString(peekToken()));
	}
	return null;
}
private boolean maybeEatMethodOrProperty(boolean nullSafeNavigation) {
	//如果Token类型是TokenKind.IDENTIFIER,确实round类型是TokenKind.IDENTIFIER
	if (peekToken(TokenKind.IDENTIFIER)) {
		//next Token是方法或者属性
		Token methodOrPropertyName = nextToken();
		//获取方法参数
		SpelNodeImpl[] args = maybeEatMethodArgs();
		if (args==null) {
			// property
			push(new PropertyOrFieldReference(nullSafeNavigation, methodOrPropertyName.data,toPos(methodOrPropertyName)));
			return true;
		}
		//返回方法引用
		push(new MethodReference(nullSafeNavigation, methodOrPropertyName.data, toPos(methodOrPropertyName), args));
		// TODO what is the end position for a method reference? the name or the last arg?
		return true;
	}
	return false;
}
private SpelNodeImpl[] maybeEatMethodArgs() {
	if (!peekToken(TokenKind.LPAREN)) {
		return null;
	}
	List<SpelNodeImpl> args = new ArrayList<SpelNodeImpl>();
	consumeArguments(args);
	eatToken(TokenKind.RPAREN);
	return args.toArray(new SpelNodeImpl[args.size()]);
}
private void consumeArguments(List accumulatedArguments) {
	int pos = peekToken().startPos;
	Token next;
	do {
		// 下一个token , 本例中是 ) 
		nextToken();  // consume ( (first time through) or comma (subsequent times)
		Token t = peekToken();
		if (t == null) {
			raiseInternalException(pos, SpelMessage.RUN_OUT_OF_ARGUMENTS);
		}
		// 是不是右括号
		if (t.kind != TokenKind.RPAREN) {
			// 如果是右括号,继续递归吃掉括号内的表达式 30d 
			accumulatedArguments.add(eatExpression());
		}
		next = peekToken();
	}
	while (next != null && next.kind == TokenKind.COMMA);
	if (next == null) {
		raiseInternalException(pos, SpelMessage.RUN_OUT_OF_ARGUMENTS);
	}
}

方法参数30d 最后解析得到RealLiteral对象
在这里插入图片描述
因为nodes参数中第一个是TypeReference,第二个参数是MethodReference,因此,返回一个复杂对象,CompoundExpression对象。
在这里,我们终于将表达式吃吃完了,那我们最终得到了什么呢,如下图所示
在这里插入图片描述

在这里插入图片描述
最终返回CompositeStringExpression对象。终于将表达式吃完了,这里,我们继续来分析值的获取 。

CompositeStringExpression.java

@Override
public  T getValue(Class expectedResultType) throws EvaluationException {
	Object value = getValue();
	// 类型转换
	return ExpressionUtils.convertTypedValue(null, new TypedValue(value), expectedResultType);
}
@Override
public String getValue() throws EvaluationException {
	StringBuilder sb = new StringBuilder();
	for (Expression expression : this.expressions) {
		String value = expression.getValue(String.class);
		if (value != null) {
			sb.append(value);
		}
	}
	return sb.toString();
}

通过上面可以看出,最终我们random number is #{T(java.lang.Math).round(30d)} 是通过
random number is和(java.lang.Math).round(30d) 表达式各自计算出的结果再通过append拼接在一起的。
random number is对应的是LiteralExpression,调用getValue()方法。

LiteralExpression.java

@Override
public String getValue() {
	//直接返回value值
	return this.literalValue;
}

我们再来看看CompoundExpression表达式的getValue()方法

SpelExpression.java

@Override
public  T getValue(Class expectedResultType) throws EvaluationException {
	if (this.compiledAst != null) {
		try {
			TypedValue contextRoot = evaluationContext == null ? null : evaluationContext.getRootObject();
			Object result = this.compiledAst.getValue(contextRoot == null ? null : contextRoot.getValue(), evaluationContext);
			if (expectedResultType == null) {
				return (T)result;
			}
			else {
				return ExpressionUtils.convertTypedValue(getEvaluationContext(), new TypedValue(result), expectedResultType);
			}
		}
		catch (Throwable ex) {
			// If running in mixed mode, revert to interpreted
			if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
				this.interpretedCount = 0;
				this.compiledAst = null;
			}
			else {
				// Running in SpelCompilerMode.immediate mode - propagate exception to caller
				throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION);
			}
		}
	}
	//初始化表达式数据
	ExpressionState expressionState = new ExpressionState(getEvaluationContext(), this.configuration);
	//获取返回值
	TypedValue typedResultValue = this.ast.getTypedValue(expressionState);
	checkCompile(expressionState);
	//类型转换
	return ExpressionUtils.convertTypedValue(expressionState.getEvaluationContext(), typedResultValue, expectedResultType);
}

SpelNodeImpl.java

@Override
public final TypedValue getTypedValue(ExpressionState expressionState) throws EvaluationException {
	if (expressionState != null) {
		//expressionState not null
		return getValueInternal(expressionState);
	}
	else {
		// configuration not set - does that matter?
		return getTypedValue(new ExpressionState(new StandardEvaluationContext()));
	}
}

CompoundExpression.java

@Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
	//获取值引用
	ValueRef ref = getValueRef(state);
	TypedValue result = ref.getValue();
	this.exitTypeDescriptor = this.children[this.children.length - 1].exitTypeDescriptor;
	return result;
}

CompoundExpression.java

@Override
protected ValueRef getValueRef(ExpressionState state) throws EvaluationException {
	//如果this只有一个child
	if (getChildCount() == 1) {
		return this.children[0].getValueRef(state);
	}
	//在本例中,第一个参数是TypeReference,因此下面调用TypeReference的getValueInternal方法
	SpelNodeImpl nextNode = this.children[0];
	try {
		TypedValue result = nextNode.getValueInternal(state);
		int cc = getChildCount();
		for (int i = 1; i < cc - 1; i++) {
			try {
				state.pushActiveContextObject(result);
				nextNode = this.children[i];
				result = nextNode.getValueInternal(state);
			}
			finally {
				state.popActiveContextObject();
			}
		}
		try {
			state.pushActiveContextObject(result);
			nextNode = this.children[cc-1];
			//调用方法引用的getValueRef
			return nextNode.getValueRef(state);
		}
		finally {
			state.popActiveContextObject();
		}
	}
	catch (SpelEvaluationException ex) {
		ex.setPosition(nextNode.getStartPosition());
		throw ex;
	}
}

TypeReference.java

@Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
	// TODO possible optimization here if we cache the discovered type reference, but can we do that? 
	//本例中 第一个child是QualifiedIdentifier ,因此调用QualifiedIdentifier的getValueInternal方法,得到了java.lang.Math对象
	String typeName = (String) this.children[0].getValueInternal(state).getValue();
	if (!typeName.contains(".") && Character.isLowerCase(typeName.charAt(0))) {
		TypeCode tc = TypeCode.valueOf(typeName.toUpperCase());
		if (tc != TypeCode.OBJECT) {
			// It is a primitive type 
			Class<?> clazz = makeArrayIfNecessary(tc.getType());
			this.exitTypeDescriptor = "Ljava/lang/Class";
			this.type = clazz;
			return new TypedValue(clazz);
		}
	}
	//最终在内部通过反射拿到java.lang.Math类型
	Class<?> clazz = state.findType(typeName);
	//如果是集合类型,则转换成集合类型
	clazz = makeArrayIfNecessary(clazz);
	this.exitTypeDescriptor = "Ljava/lang/Class";
	this.type = clazz;
	return new TypedValue(clazz);
}

QualifiedIdentifier.java

@Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
	//这个方法内部其实很简单,就是将child用逗号隔开拼接起来
	if (this.value == null) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < getChildCount(); i++) {
			Object value = this.children[i].getValueInternal(state).getValue();
			if (i > 0 && !value.toString().startsWith("$")) {
				sb.append(".");
			}
			sb.append(value);
		}
		this.value = new TypedValue(sb.toString());
	}
	return this.value;
}

上面己经完成了QualifiedIdentifier的解析,下面来解析MethodReference

MethodReference.java

@Override
protected ValueRef getValueRef(ExpressionState state) throws EvaluationException {
	Object[] arguments = getArguments(state);
	if (state.getActiveContextObject().getValue() == null) {
		throwIfNotNullSafe(getArgumentTypes(arguments));
		return ValueRef.NullValueRef.INSTANCE;
	}
	return new MethodValueRef(state, arguments);
}

MethodReference.java

private Object[] getArguments(ExpressionState state) {
	Object[] arguments = new Object[getChildCount()];
	for (int i = 0; i < arguments.length; i++) {
		try {
			state.pushActiveContextObject(state.getScopeRootContextObject());
			//获取方法参数的getValueInternal方法,
			//这里我们是获取30d 的类型,RealLiteral 的getValueInternal方法,
			//再调用getValue()方法,返回 Double(30) 
			arguments[i] = this.children[i].getValueInternal(state).getValue();
		}
		finally {
			state.popActiveContextObject();
		}
	}
	return arguments;
}

在这里插入图片描述
获取MethodValueRef对象,调用MethodValueRef的getValue()方法

MethodValueRef.java

@Override
public TypedValue getValue() {
	TypedValue result = MethodReference.this.getValueInternal(
			this.evaluationContext, this.value, this.targetType, this.arguments);
	updateExitTypeDescriptor();
	return result;
}

MethodReference.java

private TypedValue getValueInternal(EvaluationContext evaluationContext,
		Object value, TypeDescriptor targetType, Object[] arguments) {
	//获取参数类型 
	List<TypeDescriptor> argumentTypes = getArgumentTypes(arguments);
	if (value == null) {
		throwIfNotNullSafe(argumentTypes);
		return TypedValue.NULL;
	}
	//从缓存中获取 
	MethodExecutor executorToUse = getCachedExecutor(evaluationContext, value, targetType, argumentTypes);
	if (executorToUse != null) {
		try {
			return executorToUse.execute(evaluationContext, value, arguments);
		}
		catch (AccessException ex) {
			throwSimpleExceptionIfPossible(value, ex);
			this.cachedExecutor = null;
		}
	}
	//获取执行方法
	executorToUse = findAccessorForMethod(this.name, argumentTypes, value, evaluationContext);
	this.cachedExecutor = new CachedMethodExecutor(
			executorToUse, (value instanceof Class ? (Class<?>) value : null), targetType, argumentTypes);
	try {
		return executorToUse.execute(evaluationContext, value, arguments);
	}
	catch (AccessException ex) {
		throwSimpleExceptionIfPossible(value, ex);
		throw new SpelEvaluationException(getStartPosition(), ex,
				SpelMessage.EXCEPTION_DURING_METHOD_INVOCATION, this.name,
				value.getClass().getName(), ex.getMessage());
	}
}
private List getArgumentTypes(Object... arguments) {
	List descriptors = new ArrayList(arguments.length);
	for (Object argument : arguments) {
		descriptors.add(TypeDescriptor.forObject(argument));
	}
	return Collections.unmodifiableList(descriptors);
}

MethodReference.java

private MethodExecutor findAccessorForMethod(String name, List argumentTypes,
		Object targetObject, EvaluationContext evaluationContext) throws SpelEvaluationException {
		
	List methodResolvers = evaluationContext.getMethodResolvers();
	if (methodResolvers != null) {
		for (MethodResolver methodResolver : methodResolvers) {
			try {
				MethodExecutor methodExecutor = methodResolver.resolve(
						evaluationContext, targetObject, name, argumentTypes);
				if (methodExecutor != null) {
					return methodExecutor;
				}
			}
			catch (AccessException ex) {
				throw new SpelEvaluationException(getStartPosition(), ex,
						SpelMessage.PROBLEM_LOCATING_METHOD, name, targetObject.getClass());
			}
		}
	}

	throw new SpelEvaluationException(getStartPosition(), SpelMessage.METHOD_NOT_FOUND,
			FormatHelper.formatMethodForMessage(name, argumentTypes),
			FormatHelper.formatClassNameForMessage(
					targetObject instanceof Class ? ((Class<?>) targetObject) : targetObject.getClass()));
}

前面的解析中己经分析了,默认是ReflectiveMethodResolver来调用resolve

@Override
public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
		List argumentTypes) throws AccessException {
	try {
		TypeConverter typeConverter = context.getTypeConverter();
		Class<?> type = (targetObject instanceof Class ? (Class<?>) targetObject : targetObject.getClass());
		//获取目标类的所有方法
		List methods = new ArrayList(getMethods(type, targetObject));

		MethodFilter filter = (this.filters != null ? this.filters.get(type) : null);
		if (filter != null) {
			List filtered = filter.filter(methods);
			methods = (filtered instanceof ArrayList ? filtered : new ArrayList(filtered));
		}

		if (methods.size() > 1) {
			Collections.sort(methods, new Comparator() {
				@Override
				public int compare(Method m1, Method m2) {
					int m1pl = m1.getParameterTypes().length;
					int m2pl = m2.getParameterTypes().length;
					// varargs methods go last
					if (m1pl == m2pl) {
					    if (!m1.isVarArgs() && m2.isVarArgs()) {
					    	return -1;
					    }
					    else if (m1.isVarArgs() && !m2.isVarArgs()) {
					    	return 1;
					    }
					    else {
					    	return 0;
					    }
					}
					return (m1pl < m2pl ? -1 : (m1pl > m2pl ? 1 : 0));
				}
			});
		}

		for (int i = 0; i < methods.size(); i++) {
			methods.set(i, BridgeMethodResolver.findBridgedMethod(methods.get(i)));
		}
		
		Set methodsToIterate = new LinkedHashSet(methods);

		Method closeMatch = null;
		int closeMatchDistance = Integer.MAX_VALUE;
		Method matchRequiringConversion = null;
		boolean multipleOptions = false;

		for (Method method : methodsToIterate) {
			if (method.getName().equals(name)) {
				Class<?>[] paramTypes = method.getParameterTypes();
				List paramDescriptors = new ArrayList(paramTypes.length);
				for (int i = 0; i < paramTypes.length; i++) {
					paramDescriptors.add(new TypeDescriptor(new MethodParameter(method, i)));
				}
				ReflectionHelper.ArgumentsMatchInfo matchInfo = null;
				//如果匹配方法是可变参数,那么我们配置的表达式中的参数个数一定大于等于方法参数的个数
				if (method.isVarArgs() && argumentTypes.size() >= (paramTypes.length - 1)) {
					matchInfo = ReflectionHelper.compareArgumentsVarargs(paramDescriptors, argumentTypes, typeConverter);
				}
				//不是可变参数方法 
				else if (paramTypes.length == argumentTypes.size()) {
					matchInfo = ReflectionHelper.compareArguments(paramDescriptors, argumentTypes, typeConverter);
				}
				if (matchInfo != null) {
					if (matchInfo.isExactMatch()) {
						return new ReflectiveMethodExecutor(method);
					}
					else if (matchInfo.isCloseMatch()) {
						if (this.useDistance) {
							int matchDistance = ReflectionHelper.getTypeDifferenceWeight(paramDescriptors, argumentTypes);
							if (closeMatch == null || matchDistance < closeMatchDistance) {
								// This is a better match...
								closeMatch = method;
								closeMatchDistance = matchDistance;
							}
						}
						else {
							// Take this as a close match if there isn't one already
							if (closeMatch == null) {
								closeMatch = method;
							}
						}
					}
					else if (matchInfo.isMatchRequiringConversion()) {
						if (matchRequiringConversion != null) {
							multipleOptions = true;
						}
						matchRequiringConversion = method;
					}
				}
			}
		}
		if (closeMatch != null) {
			return new ReflectiveMethodExecutor(closeMatch);
		}
		else if (matchRequiringConversion != null) {
			if (multipleOptions) {
				throw new SpelEvaluationException(SpelMessage.MULTIPLE_POSSIBLE_METHODS, name);
			}
			return new ReflectiveMethodExecutor(matchRequiringConversion);
		}
		else {
			return null;
		}
	}
	catch (EvaluationException ex) {
		throw new AccessException("Failed to resolve method", ex);
	}
}

ReflectionHelper.java

static ArgumentsMatchInfo compareArguments(
		List expectedArgTypes, List suppliedArgTypes, TypeConverter typeConverter) {

	Assert.isTrue(expectedArgTypes.size() == suppliedArgTypes.size(),
			"Expected argument types and supplied argument types should be arrays of same length");

	ArgumentsMatchKind match = ArgumentsMatchKind.EXACT;
	for (int i = 0; i < expectedArgTypes.size() && match != null; i++) {
		TypeDescriptor suppliedArg = suppliedArgTypes.get(i);
		TypeDescriptor expectedArg = expectedArgTypes.get(i);
		//匹配到的方法参数类型,和我们配置方法中的参数类型比对
		if (!expectedArg.equals(suppliedArg)) {
			if (suppliedArg == null) {
				if (expectedArg.isPrimitive()) {
					match = null;
				}
			}
			else {
				//配制方法参数类型isAssignableFrom 匹配到的方法参数类型
				// suppliedArg =  Double ,expectedArg = double
				if (suppliedArg.isAssignableTo(expectedArg)) {
					if (match != ArgumentsMatchKind.REQUIRES_CONVERSION) {
						match = ArgumentsMatchKind.CLOSE;
					}
				}
				else if (typeConverter.canConvert(suppliedArg, expectedArg)) {
					match = ArgumentsMatchKind.REQUIRES_CONVERSION;
				}
				else {
					match = null;
				}
			}
		}
	}
	return (match != null ? new ArgumentsMatchInfo(match) : null);
}

ReflectionHelper.java

public static int getTypeDifferenceWeight(List paramTypes, List argTypes) {
	//获取类型权重
	int result = 0;
	for (int i = 0; i < paramTypes.size(); i++) {
		TypeDescriptor paramType = paramTypes.get(i);
		TypeDescriptor argType = (i < argTypes.size() ? argTypes.get(i) : null);
		if (argType == null) {
			if (paramType.isPrimitive()) {
				return Integer.MAX_VALUE;
			}
		}
		else {
			Class<?> paramTypeClazz = paramType.getType();
			if (!ClassUtils.isAssignable(paramTypeClazz, argType.getType())) {
				return Integer.MAX_VALUE;
			}
			if (paramTypeClazz.isPrimitive()) {
				paramTypeClazz = Object.class;
			}
			Class<?> superClass = argType.getType().getSuperclass();
			while (superClass != null) {
				if (paramTypeClazz.equals(superClass)) {
					result = result + 2;
					superClass = null;
				}
				else if (ClassUtils.isAssignable(paramTypeClazz, superClass)) {
					result = result + 2;
					superClass = superClass.getSuperclass();
				}
				else {
					superClass = null;
				}
			}
			if (paramTypeClazz.isInterface()) {
				result = result + 1;
			}
		}
	}
	return result;
}

上面己经获取到了Math类的round方法,下面将通过反射来调用round方法

ReflectiveMethodExecutor.java

@Override
public TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException {
	try {
		if (arguments != null) {
			//将配置方法的类型转化成匹配到的方法类型
			this.argumentConversionOccurred = ReflectionHelper.convertArguments(context.getTypeConverter(), arguments, this.method, this.varargsPosition);
		}
		if (this.method.isVarArgs()) {
			arguments = ReflectionHelper.setupArgumentsForVarargsInvocation(this.method.getParameterTypes(), arguments);
		}
		ReflectionUtils.makeAccessible(this.method);
		//反射调用相关的方法 ,得到计算值 30
		Object value = this.method.invoke(target, arguments);
		return new TypedValue(value, new TypeDescriptor(new MethodParameter(this.method, -1)).narrow(value));
	}
	catch (Exception ex) {
		throw new AccessException("Problem invoking method: " + this.method, ex);
	}
}

接下来将得到值30 的 Long类型转换成 目标类型String类型
到这里,我们终于解析完成
在这里插入图片描述
最后得到的值是random number is 30

其实这篇博客和第二篇博客的实现方式十分相似。
1.分词
2.解析
3.获取到目标类相匹配的方法。
4.通过反射调用匹配到的方法
5.类型转换,将方法返回值转换成用户需要的值。

Spel表达式源码解析到这里己经告一段落,如果感兴趣的小伙伴,可以下载我的源码,自己写一个,像我的思路,一步步解析,最后得到Spel的值,希望,你能得到你想要的东西。

本文的github地址是
https://github.com/quyixiao/spring_tiny/blob/master/src/main/java/com/spring_101_200/test_111_120/test_113_conversion/spel/TestSpel.java

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值