Spring Expression Language 解析器
SPEL解析過程
使用 ExpressionParser 基於 ParserContext 將字符串解析爲 Expression,
Expression 再根據 EvaluationContext 計算表達式的值。
StandardBeanExpressionResolver#
/** 默認表達式前綴 */
public static final String DEFAULT_EXPRESSION_PREFIX = "#{";
/** 默認表達式後綴 */
public static final String DEFAULT_EXPRESSION_SUFFIX = "}";
/**
* 表達式前綴
*/
private String expressionPrefix = DEFAULT_EXPRESSION_PREFIX;
/**
* 表達式後綴
*/
private String expressionSuffix = DEFAULT_EXPRESSION_SUFFIX;
/**
* 表達式解析器
*/
private ExpressionParser expressionParser;
/**
* 表達式緩存
*/
private final Map<String, Expression> expressionCache = new ConcurrentHashMap<>(256);
/**
* 評估緩存
*/
private final Map<BeanExpressionContext, StandardEvaluationContext> evaluationCache = new ConcurrentHashMap<>(8);
/**
* 解析上下文
*/
private final ParserContext beanExpressionParserContext = new ParserContext() {
@Override
public boolean isTemplate() {
return true;
}
@Override
public String getExpressionPrefix() {
return expressionPrefix;
}
@Override
public String getExpressionSuffix() {
return expressionSuffix;
}
};
@Override
@Nullable
public Object evaluate(@Nullable String value, BeanExpressionContext evalContext) throws BeansException {
// value 爲 null 或空字符串
if (!StringUtils.hasLength(value)) {
return value;
}
try {
// 嘗試從緩存中讀取指定的表達式
Expression expr = expressionCache.get(value);
if (expr == null) {
// 使用表達式解析器解析此表達式
expr = expressionParser.parseExpression(value, beanExpressionParserContext);
// 加入緩存
expressionCache.put(value, expr);
}
// 讀取表達式解析上下文
StandardEvaluationContext sec = evaluationCache.get(evalContext);
if (sec == null) {
// 初始化解析上下文
sec = new StandardEvaluationContext(evalContext);
// 加載一系列的屬性訪問器
sec.addPropertyAccessor(new BeanExpressionContextAccessor());
sec.addPropertyAccessor(new BeanFactoryAccessor());
sec.addPropertyAccessor(new MapAccessor());
sec.addPropertyAccessor(new EnvironmentAccessor());
sec.setBeanResolver(new BeanFactoryResolver(evalContext.getBeanFactory()));
sec.setTypeLocator(new StandardTypeLocator(evalContext.getBeanFactory().getBeanClassLoader()));
// 類型轉換服務不爲空,則將其寫入 StandardEvaluationContext 中
final ConversionService conversionService = evalContext.getBeanFactory().getConversionService();
if (conversionService != null) {
sec.setTypeConverter(new StandardTypeConverter(conversionService));
}
// 允許子類實現自定義配置的鉤子函數
customizeEvaluationContext(sec);
// 寫入緩存
evaluationCache.put(evalContext, sec);
}
// 在標準的解析上下文中解析此表達式
return expr.getValue(sec);
}
catch (final Throwable ex) {
throw new BeanExpressionException("Expression parsing failed", ex);
}
}
TemplateAwareExpressionParser#
@Override
public Expression parseExpression(String expressionString, @Nullable ParserContext context) throws ParseException {
// 默認爲 true
if (context != null && context.isTemplate()) {
return parseTemplate(expressionString, context);
}
else {
return doParseExpression(expressionString, context);
}
}
private Expression parseTemplate(String expressionString, ParserContext context) throws ParseException {
// 表達式字符串爲空,則返回字面值表達式
if (expressionString.isEmpty()) {
return new LiteralExpression("");
}
final Expression[] expressions = parseExpressions(expressionString, context);
if (expressions.length == 1) {
return expressions[0];
}
else {
return new CompositeStringExpression(expressionString, expressions);
}
}
/**
* 使用配置的解析器解析給定表達式字符串的助手
*/
private Expression[] parseExpressions(String expressionString, ParserContext context) throws ParseException {
final List<Expression> expressions = new ArrayList<>();
// 讀取表達式前綴
final String prefix = context.getExpressionPrefix();
// 讀取表達式後綴
final String suffix = context.getExpressionSuffix();
// 起始索引
int startIdx = 0;
// 起始索引 < 表達式長度
while (startIdx < expressionString.length()) {
// 計算前綴索引
final int prefixIndex = expressionString.indexOf(prefix, startIdx);
// 前綴索引 > 起始索引
if (prefixIndex >= startIdx) {
// #{} 之前存在常量字符串,則創建字面值表達式並寫入 expressions
if (prefixIndex > startIdx) {
expressions.add(new LiteralExpression(expressionString.substring(startIdx, prefixIndex)));
}
// 計算前綴之後的索引
final int afterPrefixIndex = prefixIndex + prefix.length();
// 計算後綴索引
final int suffixIndex = skipToCorrectEndSuffix(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);
// 去除前後空格
expr = expr.trim();
if (expr.isEmpty()) {
throw new ParseException(expressionString, prefixIndex,
"No expression defined within delimiter '" + prefix + suffix +
"' at character " + prefixIndex);
}
// 將截取的字符串在指定的上下文中解析成表達式
expressions.add(doParseExpression(expr, context));
// 計算新的後綴
startIdx = suffixIndex + suffix.length();
}
else {
// 在表達式字符串中沒有發現 #{expressions},則寫入字面值表達式
expressions.add(new LiteralExpression(expressionString.substring(startIdx)));
startIdx = expressionString.length();
}
}
// 返回解析成功的表達式
return expressions.toArray(new Expression[0]);
}
/**
* 校驗 () [] {} 是否一一配對,並讀取 #{expressions} 正確的後綴索引
*/
private int skipToCorrectEndSuffix(String suffix, String expressionString, int afterPrefixIndex)
throws ParseException {
/**
* Chew on the expression text - relying on the rules:
* brackets must be in pairs: () [] {}
* string literals are "..." or '...' and these may contain unmatched brackets
*/
// 前綴之後的字符索引
int pos = afterPrefixIndex;
// #{expressions} 的最大長度
final int maxlen = expressionString.length();
// 讀取下一個後綴索引
final int nextSuffix = expressionString.indexOf(suffix, afterPrefixIndex);
if (nextSuffix == -1) {
return -1; // the suffix is missing
}
final Deque<Bracket> stack = new ArrayDeque<>();
while (pos < maxlen) {
// 後綴索引是否在當前索引處 && 棧爲空
if (isSuffixHere(expressionString, pos, suffix) && stack.isEmpty()) {
break;
}
// 如果 #{expressions} 內部存在 {} [] () 等子表達式
final char ch = expressionString.charAt(pos);
switch (ch) {
case '{':
case '[':
case '(':
// 前綴 Bracket 入棧
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
final 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 '"':
// 讀取 ' 或 " 的匹配字符索引
final 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
pos = endLiteral;
break;
}
// 處理下一個字符
pos++;
}
// 存在未配對的 { [ (
if (!stack.isEmpty()) {
final 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;
}
/**
* 特定的後綴 suffix 是否在 pos 索引處
*/
private boolean isSuffixHere(String expressionString, int pos, String suffix) {
int suffixPosition = 0;
// 從 pos 索引開始,逐個字符和 suffix 進行比較
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#
/**
* 將表達式字符串解析爲 SPEL 表達式
*/
@Override
protected SpelExpression doParseExpression(String expressionString, @Nullable ParserContext context) throws ParseException {
return new InternalSpelExpressionParser(configuration).doParseExpression(expressionString, context);
}
Bean 表達式解析器
/**
* 策略接口:用於在指定的上下文中計算表達式的值
*/
public interface BeanExpressionResolver {
/**
* 將表達式解析爲指定的值,或原樣返回
*/
@Nullable
Object evaluate(@Nullable String value, BeanExpressionContext evalContext) throws BeansException;
}
- org.springframework.context.expression.StandardBeanExpressionResolver:標準 Bean 表達式解析器
/**
* 使用 Spring 表達式解析模塊解析 SPEL
*/
public class StandardBeanExpressionResolver implements BeanExpressionResolver {
/** 默認表達式前綴 */
public static final String DEFAULT_EXPRESSION_PREFIX = "#{";
/** 默認表達式後綴 */
public static final String DEFAULT_EXPRESSION_SUFFIX = "}";
/**
* 表達式前綴
*/
private String expressionPrefix = DEFAULT_EXPRESSION_PREFIX;
/**
* 表達式後綴
*/
private String expressionSuffix = DEFAULT_EXPRESSION_SUFFIX;
/**
* 表達式解析器
*/
private ExpressionParser expressionParser;
/**
* 表達式緩存
*/
private final Map<String, Expression> expressionCache = new ConcurrentHashMap<>(256);
/**
* 評估緩存
*/
private final Map<BeanExpressionContext, StandardEvaluationContext> evaluationCache = new ConcurrentHashMap<>(8);
/**
* 解析上下文
*/
private final ParserContext beanExpressionParserContext = new ParserContext() {
@Override
public boolean isTemplate() {
return true;
}
@Override
public String getExpressionPrefix() {
return expressionPrefix;
}
@Override
public String getExpressionSuffix() {
return expressionSuffix;
}
};
public StandardBeanExpressionResolver() {
expressionParser = new SpelExpressionParser();
}
public StandardBeanExpressionResolver(@Nullable ClassLoader beanClassLoader) {
expressionParser = new SpelExpressionParser(new SpelParserConfiguration(null, beanClassLoader));
}
/**
* Set the prefix that an expression string starts with.
* The default is "#{".
*/
public void setExpressionPrefix(String expressionPrefix) {
Assert.hasText(expressionPrefix, "Expression prefix must not be empty");
this.expressionPrefix = expressionPrefix;
}
/**
* Set the suffix that an expression string ends with.
* The default is "}".
*/
public void setExpressionSuffix(String expressionSuffix) {
Assert.hasText(expressionSuffix, "Expression suffix must not be empty");
this.expressionSuffix = expressionSuffix;
}
/**
* Specify the EL parser to use for expression parsing.
* <p>Default is a {@link org.springframework.expression.spel.standard.SpelExpressionParser},
* compatible with standard Unified EL style expression syntax.
*/
public void setExpressionParser(ExpressionParser expressionParser) {
Assert.notNull(expressionParser, "ExpressionParser must not be null");
this.expressionParser = expressionParser;
}
@Override
@Nullable
public Object evaluate(@Nullable String value, BeanExpressionContext evalContext) throws BeansException {
if (!StringUtils.hasLength(value)) {
return value;
}
try {
// 嘗試從緩存中讀取指定的表達式
Expression expr = expressionCache.get(value);
if (expr == null) {
// 使用表達式解析器解析此表達式
expr = expressionParser.parseExpression(value, beanExpressionParserContext);
// 加入緩存
expressionCache.put(value, expr);
}
// 讀取表達式解析上下文
StandardEvaluationContext sec = evaluationCache.get(evalContext);
if (sec == null) {
// 初始化解析上下文
sec = new StandardEvaluationContext(evalContext);
sec.addPropertyAccessor(new BeanExpressionContextAccessor());
sec.addPropertyAccessor(new BeanFactoryAccessor());
sec.addPropertyAccessor(new MapAccessor());
sec.addPropertyAccessor(new EnvironmentAccessor());
sec.setBeanResolver(new BeanFactoryResolver(evalContext.getBeanFactory()));
sec.setTypeLocator(new StandardTypeLocator(evalContext.getBeanFactory().getBeanClassLoader()));
final ConversionService conversionService = evalContext.getBeanFactory().getConversionService();
if (conversionService != null) {
sec.setTypeConverter(new StandardTypeConverter(conversionService));
}
customizeEvaluationContext(sec);
evaluationCache.put(evalContext, sec);
}
// 在標準的解析上下文中解析此表達式
return expr.getValue(sec);
}
catch (final Throwable ex) {
throw new BeanExpressionException("Expression parsing failed", ex);
}
}
/**
* Template method for customizing the expression evaluation context.
* <p>The default implementation is empty.
*/
protected void customizeEvaluationContext(StandardEvaluationContext evalContext) {
}
}
表達式解析器
- org.springframework.expression.ExpressionParser:表達式解析器抽象
/**
* 將表達式字符串解析爲可計算的已編譯表達式。
* 支持解析模板和標準表達式字符串。
*/
public interface ExpressionParser {
/**
* 將表達式字符串解析爲可計算的已編譯表達式
*/
Expression parseExpression(String expressionString) throws ParseException;
/**
* 將表達式字符串解析爲可計算的已編譯表達式,可指定解析上下文
*/
Expression parseExpression(String expressionString, ParserContext context) throws ParseException;
}
- org.springframework.expression.spel.standard.SpelExpressionParser:SPEL 表達式解析器
/**
* SpEL parser. Instances are reusable and thread-safe.
* 此實例是線程安全的
*/
public class SpelExpressionParser extends TemplateAwareExpressionParser {
/**
* 將表達式字符串解析爲 SPEL 表達式
*/
@Override
protected SpelExpression doParseExpression(String expressionString, @Nullable ParserContext context) throws ParseException {
return new InternalSpelExpressionParser(configuration).doParseExpression(expressionString, context);
}
}
public abstract class TemplateAwareExpressionParser implements ExpressionParser {
@Override
public Expression parseExpression(String expressionString, @Nullable ParserContext context) throws ParseException {
// 默認爲 true
if (context != null && context.isTemplate()) {
return parseTemplate(expressionString, context);
}
else {
return doParseExpression(expressionString, context);
}
}
private Expression parseTemplate(String expressionString, ParserContext context) throws ParseException {
// 表達式字符串爲空,則返回字面值表達式
if (expressionString.isEmpty()) {
return new LiteralExpression("");
}
final Expression[] expressions = parseExpressions(expressionString, context);
if (expressions.length == 1) {
return expressions[0];
}
else {
return new CompositeStringExpression(expressionString, expressions);
}
}
/**
* 使用配置的解析器解析給定表達式字符串的助手
*/
private Expression[] parseExpressions(String expressionString, ParserContext context) throws ParseException {
final List<Expression> expressions = new ArrayList<>();
// 讀取表達式前綴
final String prefix = context.getExpressionPrefix();
// 讀取表達式後綴
final String suffix = context.getExpressionSuffix();
// 起始索引
int startIdx = 0;
// 起始索引 < 表達式長度
while (startIdx < expressionString.length()) {
// 計算前綴索引
final int prefixIndex = expressionString.indexOf(prefix, startIdx);
// 前綴索引 > 起始索引
if (prefixIndex >= startIdx) {
// #{} 之前存在常量字符串,則創建字面值表達式並寫入 expressions
if (prefixIndex > startIdx) {
expressions.add(new LiteralExpression(expressionString.substring(startIdx, prefixIndex)));
}
// 計算前綴之後的索引
final int afterPrefixIndex = prefixIndex + prefix.length();
// 計算後綴索引
final int suffixIndex = skipToCorrectEndSuffix(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);
// 去除前後空格
expr = expr.trim();
if (expr.isEmpty()) {
throw new ParseException(expressionString, prefixIndex,
"No expression defined within delimiter '" + prefix + suffix +
"' at character " + prefixIndex);
}
// 將截取的字符串在指定的上下文中解析成表達式
expressions.add(doParseExpression(expr, context));
// 計算新的後綴
startIdx = suffixIndex + suffix.length();
}
else {
// 在表達式字符串中沒有發現 #{expressions},則寫入字面值表達式
expressions.add(new LiteralExpression(expressionString.substring(startIdx)));
startIdx = expressionString.length();
}
}
// 返回解析成功的表達式
return expressions.toArray(new Expression[0]);
}
/**
* 特定的後綴 suffix 是否在 pos 索引處
*/
private boolean isSuffixHere(String expressionString, int pos, String suffix) {
int suffixPosition = 0;
// 從 pos 索引開始,逐個字符和 suffix 進行比較
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;
}
/**
* 校驗 () [] {} 是否一一配對,並讀取 #{expressions} 正確的後綴索引
*/
private int skipToCorrectEndSuffix(String suffix, String expressionString, int afterPrefixIndex)
throws ParseException {
/**
* Chew on the expression text - relying on the rules:
* brackets must be in pairs: () [] {}
* string literals are "..." or '...' and these may contain unmatched brackets
*/
// 前綴之後的字符索引
int pos = afterPrefixIndex;
// #{expressions} 的最大長度
final int maxlen = expressionString.length();
// 讀取下一個後綴索引
final int nextSuffix = expressionString.indexOf(suffix, afterPrefixIndex);
if (nextSuffix == -1) {
return -1; // the suffix is missing
}
final Deque<Bracket> stack = new ArrayDeque<>();
while (pos < maxlen) {
// 後綴索引是否在當前索引處 && 棧爲空
if (isSuffixHere(expressionString, pos, suffix) && stack.isEmpty()) {
break;
}
// 如果 #{expressions} 內部存在 {} [] () 等子表達式
final char ch = expressionString.charAt(pos);
switch (ch) {
case '{':
case '[':
case '(':
// 前綴 Bracket 入棧
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
final 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 '"':
// 讀取 ' 或 " 的匹配字符索引
final 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
pos = endLiteral;
break;
}
// 處理下一個字符
pos++;
}
// 存在未配對的 { [ (
if (!stack.isEmpty()) {
final 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;
}
/**
* 捕獲指定的括號類型並記錄其在表達式中的位置
*/
private static class Bracket {
/**
* 括號字符
*/
char bracket;
/**
* 括號字符在表達式中的索引
*/
int pos;
Bracket(char bracket, int pos) {
this.bracket = bracket;
this.pos = pos;
}
/**
* 計算結束括號
*/
boolean compatibleWithCloseBracket(char closeBracket) {
if (bracket == '{') {
return closeBracket == '}';
}
else if (bracket == '[') {
return closeBracket == ']';
}
return closeBracket == ')';
}
/**
* 計算起始括號
*/
static char theOpenBracketFor(char closeBracket) {
if (closeBracket == '}') {
return '{';
}
else if (closeBracket == ']') {
return '[';
}
return '(';
}
/**
* 計算結束括號
*/
static char theCloseBracketFor(char openBracket) {
if (openBracket == '{') {
return '}';
}
else if (openBracket == '[') {
return ']';
}
return ')';
}
}
}
解析上下文
- org.springframework.expression.ParserContext:解析上下文
/**
* 解析上下文
*/
public interface ParserContext {
/**
* 被解析的表達式是否爲模板
*/
boolean isTemplate();
/**
* 模板表達式的前綴
*/
String getExpressionPrefix();
/**
* 模板表達式的後綴
*/
String getExpressionSuffix();
/**
* The default ParserContext implementation that enables template expression
* parsing mode. The expression prefix is "#{" and the expression suffix is "}".
* @see #isTemplate()
*/
ParserContext TEMPLATE_EXPRESSION = new ParserContext() {
@Override boolean isTemplate() {
return true;
}
@Override String getExpressionPrefix() {
return "#{";
}
@Override String getExpressionSuffix() {
return "}";
}
};
}
Bean 表達式上下文
public class BeanExpressionContext {
/**
* Bean 表達式解析上限文,默認的 beanFactory
* org.springframework.beans.factory.support.DefaultListableBeanFactory
*/
private final ConfigurableBeanFactory beanFactory;
/**
* 作用域
*/
@Nullable
private final Scope scope;
}
表達式
- org.springframework.expression.Expression:表達式抽象
/**
* 能夠根據上下文對象評估自身的表達式。
* 封裝了先前解析的表達式字符串的詳細信息。
* 提供表達式求值的公共抽象。
*/
public interface Expression {
/**
* 返回用於創建表達式的原始字符串
*/
String getExpressionString();
/**
* 在默認的標準上下文中計算這個表達式
*/
@Nullable
Object getValue() throws EvaluationException;
/**
* 在默認的標準上下文中計算這個表達式,並將結果轉換爲指定的類型
*/
@Nullable
<T> T getValue(@Nullable Class<T> desiredResultType) throws EvaluationException;
/**
* 根據指定的根對象計算這個表達式
*/
@Nullable
Object getValue(Object rootObject) throws EvaluationException;
/**
* 在默認的標準上下文中,根據指定的根對象計算這個表達式
*/
@Nullable
<T> T getValue(Object rootObject, @Nullable Class<T> desiredResultType) throws EvaluationException;
/**
* 在指定的上下文中計算這個表達式
*/
@Nullable
Object getValue(EvaluationContext context) throws EvaluationException;
/**
* 在指定的上下文中,根據指定的根對象計算這個表達式
*/
@Nullable
Object getValue(EvaluationContext context, Object rootObject) throws EvaluationException;
/**
* 在指定的上下文中計算這個表達式,並將結果轉換爲指定類型
*/
@Nullable
<T> T getValue(EvaluationContext context, @Nullable Class<T> desiredResultType) throws EvaluationException;
/**
* 在指定的上下文中,根據指定的根對象計算這個表達式,並將結果轉換爲指定類型
*/
@Nullable
<T> T getValue(EvaluationContext context, Object rootObject, @Nullable Class<T> desiredResultType)
throws EvaluationException;
/**
* Return the most general type that can be passed to a {@link #setValue}
* method using the default context.
*/
@Nullable
Class<?> getValueType() throws EvaluationException;
/**
* Return the most general type that can be passed to the
* {@link #setValue(Object, Object)} method using the default context.
*/
@Nullable
Class<?> getValueType(Object rootObject) throws EvaluationException;
/**
* Return the most general type that can be passed to the
* {@link #setValue(EvaluationContext, Object)} method for the given context.
*/
@Nullable
Class<?> getValueType(EvaluationContext context) throws EvaluationException;
/**
* Return the most general type that can be passed to the
* {@link #setValue(EvaluationContext, Object, Object)} method for the given
* context. The supplied root object overrides any specified in the context.
*/
@Nullable
Class<?> getValueType(EvaluationContext context, Object rootObject) throws EvaluationException;
/**
* Return the most general type that can be passed to a {@link #setValue}
* method using the default context.
*/
@Nullable
TypeDescriptor getValueTypeDescriptor() throws EvaluationException;
/**
* Return the most general type that can be passed to the
* {@link #setValue(Object, Object)} method using the default context.
*/
@Nullable
TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException;
/**
* Return the most general type that can be passed to the
* {@link #setValue(EvaluationContext, Object)} method for the given context.
*/
@Nullable
TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException;
/**
* Return the most general type that can be passed to the
* {@link #setValue(EvaluationContext, Object, Object)} method for the given
* context. The supplied root object overrides any specified in the context.
*/
@Nullable
TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject) throws EvaluationException;
/**
* Determine if an expression can be written to, i.e. setValue() can be called.
*/
boolean isWritable(Object rootObject) throws EvaluationException;
/**
* Determine if an expression can be written to, i.e. setValue() can be called.
*/
boolean isWritable(EvaluationContext context) throws EvaluationException;
/**
* Determine if an expression can be written to, i.e. setValue() can be called.
* The supplied root object overrides any specified in the context.
*/
boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException;
/**
* Set this expression in the provided context to the value provided.
*/
void setValue(Object rootObject, @Nullable Object value) throws EvaluationException;
/**
* Set this expression in the provided context to the value provided.
*/
void setValue(EvaluationContext context, @Nullable Object value) throws EvaluationException;
/**
* Set this expression in the provided context to the value provided.
* The supplied root object overrides any specified in the context.
*/
void setValue(EvaluationContext context, Object rootObject, @Nullable Object value) throws EvaluationException;
}
- org.springframework.expression.spel.standard.SpelExpression:SPEL 表達式
public class SpelExpression implements Expression {
// 編譯表達式之前解釋表達式的次數
private static final int INTERPRETED_COUNT_THRESHOLD = 100;
// 在放棄之前嘗試編譯表達式的次數
private static final int FAILED_ATTEMPTS_THRESHOLD = 100;
/**
* 表達式
*/
private final String expression;
/**
* AST 節點,保存了已經分割的字符串
* org.springframework.expression.spel.ast.CompoundExpression
*/
private final SpelNodeImpl ast;
/**
* 解析配置
*/
private final SpelParserConfiguration configuration;
// 默認的計算上限文
@Nullable
private EvaluationContext evaluationContext;
// 已編譯的表達式
@Nullable
private CompiledExpression compiledAst;
// Count of many times as the expression been interpreted - can trigger compilation when certain limit reached
private volatile int interpretedCount = 0;
// The number of times compilation was attempted and failed - enables us to eventually give up trying to compile it when it just doesn't seem to be possible.
private volatile int failedAttempts = 0;
@Override
@Nullable
public Object getValue() throws EvaluationException {
if (compiledAst != null) {
try {
final EvaluationContext context = getEvaluationContext();
return compiledAst.getValue(context.getRootObject().getValue(), context);
}
catch (final Throwable ex) {
// If running in mixed mode, revert to interpreted
if (configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
interpretedCount = 0;
compiledAst = null;
}
else {
// Running in SpelCompilerMode.immediate mode - propagate exception to caller
throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION);
}
}
}
final ExpressionState expressionState = new ExpressionState(getEvaluationContext(), configuration);
// 解析此表達式
final Object result = ast.getValue(expressionState);
checkCompile(expressionState);
return result;
}
}
表達式計算節點
/**
* 已解析表達式的 AST 中的計算節點
*/
public interface SpelNode {
/**
* 在 ExpressionState 中計算此節點的值
*/
@Nullable
Object getValue(ExpressionState expressionState) throws EvaluationException;
/**
* 在 ExpressionState 中計算此節點的值,返回 TypedValue
*/
TypedValue getTypedValue(ExpressionState expressionState) throws EvaluationException;
/**
* 此計算節點是否支持 setValue() 調用
*/
boolean isWritable(ExpressionState expressionState) throws EvaluationException;
/**
* 將 newValue 寫入此計算節點
*/
void setValue(ExpressionState expressionState, @Nullable Object newValue) throws EvaluationException;
/**
* 返回此 AST 節點的字符串表示
*/
String toStringAST();
/**
* 此計算節點的子節點數目
*/
int getChildCount();
/**
* 返回指定索引處的 SpelNode
*/
SpelNode getChild(int index);
/**
* 返回目標對象的類型
*/
@Nullable
Class<?> getObjectClass(@Nullable Object obj);
/**
* AST node 在表達式字符串中的起始索引
*/
int getStartPosition();
/**
* AST node 在表達式字符串中的結束索引
*/
int getEndPosition();
}
- org.springframework.expression.spel.ast.SpelNodeImpl:AST 計算節點公共抽象
/**
* 已解析 SPEL 表達式所有 AST 節點的公共抽象
*/
public abstract class SpelNodeImpl implements SpelNode, Opcodes {
private static final SpelNodeImpl[] NO_CHILDREN = new SpelNodeImpl[0];
/**
* 高 16 位保存計算節點的起始索引,低 16 位保存計算節點的結束索引
*/
protected int pos; // start = top 16bits, end = bottom 16bits
protected SpelNodeImpl[] children = SpelNodeImpl.NO_CHILDREN;
/**
* 父節點
*/
@Nullable
private SpelNodeImpl parent;
/**
* 指示此表達式節點的結果類型描述符,對於字面值是立即知曉的,對於屬性訪問或方法調用,
* 需要在實際執行後才知曉
* Some examples: Ljava/lang/String, I, [I
*/
@Nullable
protected volatile String exitTypeDescriptor;
}
- org.springframework.expression.spel.ast.CompoundExpression:級聯屬性計算節點
/**
* 標識以 . 分割的表達式序列
*/
public class CompoundExpression extends SpelNodeImpl {
public CompoundExpression(int pos, SpelNodeImpl... expressionComponents) {
super(pos, expressionComponents);
if (expressionComponents.length < 2) {
throw new IllegalStateException("Do not build compound expressions with less than two entries: " +
expressionComponents.length);
}
}
/**
* 在 ExpressionState 中計算表達式的值
*/
@Override
protected ValueRef getValueRef(ExpressionState state) throws EvaluationException {
// 如果是單個子節點
if (getChildCount() == 1) {
return children[0].getValueRef(state);
}
// 讀取第一個子節點
SpelNodeImpl nextNode = children[0];
try {
// 讀取子節點的值
TypedValue result = nextNode.getValueInternal(state);
// 讀取子節點數量
final int cc = getChildCount();
// 如果存在 3 個及以上子節點,則逐個解析
for (int i = 1; i < cc - 1; i++) {
try {
state.pushActiveContextObject(result);
nextNode = children[i];
result = nextNode.getValueInternal(state);
}
finally {
state.popActiveContextObject();
}
}
try {
// 將前面子節點的結果作爲計算上下文入棧
state.pushActiveContextObject(result);
// 讀取子節點
nextNode = children[cc - 1];
// 基於前面的計算結果計算新值
return nextNode.getValueRef(state);
}
finally {
// 彈出激活的上下文
state.popActiveContextObject();
}
}
catch (final SpelEvaluationException ex) {
// Correct the position for the error before re-throwing
ex.setPosition(nextNode.getStartPosition());
throw ex;
}
}
/**
* 基於 ExpressionState 計算複合表達式的值
*/
@Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
final ValueRef ref = getValueRef(state);
// 讀取計算值
final TypedValue result = ref.getValue();
exitTypeDescriptor = children[children.length - 1].exitTypeDescriptor;
// 返回計算值
return result;
}
}
- org.springframework.expression.spel.ast.PropertyOrFieldReference:單個屬性或字段計算節點
PropertyOrFieldReference
/**
* 表示簡單的屬性或字段引用
*/
public class PropertyOrFieldReference extends SpelNodeImpl {
/**
* null 安全
*/
private final boolean nullSafe;
/**
* 字段名稱
*/
private final String name;
@Nullable
private String originalPrimitiveExitTypeDescriptor;
/**
* 讀屬性訪問器緩存
*/
@Nullable
private volatile PropertyAccessor cachedReadAccessor;
/**
* 寫屬性訪問器緩存
*/
@Nullable
private volatile PropertyAccessor cachedWriteAccessor;
/**
* 創建 AccessorLValue
*/
@Override
public ValueRef getValueRef(ExpressionState state) throws EvaluationException {
return new AccessorLValue(this, state.getActiveContextObject(), state.getEvaluationContext(),
state.getConfiguration().isAutoGrowNullReferences());
}
private TypedValue getValueInternal(TypedValue contextObject, EvaluationContext evalContext,
boolean isAutoGrowNullReferences) throws EvaluationException {
// 讀取屬性值
TypedValue result = readProperty(contextObject, evalContext, name);
return result;
}
/**
* 從當前上下文對象中讀取命名屬性
*/
private TypedValue readProperty(TypedValue contextObject, EvaluationContext evalContext, String name)
throws EvaluationException {
// 讀取目標對象
final Object targetObject = contextObject.getValue();
if (targetObject == null && nullSafe) {
return TypedValue.NULL;
}
// 是否存在讀訪問器緩存
final PropertyAccessor accessorToUse = cachedReadAccessor;
if (accessorToUse != null) {
if (evalContext.getPropertyAccessors().contains(accessorToUse)) {
try {
return accessorToUse.read(evalContext, contextObject.getValue(), name);
}
catch (final Exception ex) {
// This is OK - it may have gone stale due to a class change,
// let's try to get a new one and call it before giving up...
}
}
cachedReadAccessor = null;
}
final List<PropertyAccessor> accessorsToTry =
getPropertyAccessorsToTry(contextObject.getValue(), evalContext.getPropertyAccessors());
// 嘗試使用屬性訪問器讀取上下文中的屬性值
try {
for (PropertyAccessor accessor : accessorsToTry) {
// 當期屬性訪問器能否從上下文中讀取目標屬性
if (accessor.canRead(evalContext, contextObject.getValue(), name)) {
if (accessor instanceof ReflectivePropertyAccessor) {
accessor = ((ReflectivePropertyAccessor) accessor).createOptimalAccessor(
evalContext, contextObject.getValue(), name);
}
cachedReadAccessor = accessor;
// 讀取目標屬性的值並返回
return accessor.read(evalContext, contextObject.getValue(), name);
}
}
}
catch (final Exception ex) {
throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_DURING_PROPERTY_READ, name, ex.getMessage());
}
// 沒有一個屬性訪問器能讀取值,此 SPEL 表達式無法解析,拋出 SpelEvaluationException 異常
if (contextObject.getValue() == null) {
throw new SpelEvaluationException(SpelMessage.PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL, name);
}
else {
throw new SpelEvaluationException(getStartPosition(), SpelMessage.PROPERTY_OR_FIELD_NOT_READABLE, name,
FormatHelper.formatClassNameForMessage(getObjectClass(contextObject.getValue())));
}
}
/**
* 從 propertyAccessors 中過濾出能從 contextObject 中讀取屬性值的訪問器列表
*/
private List<PropertyAccessor> getPropertyAccessorsToTry(
@Nullable Object contextObject, List<PropertyAccessor> propertyAccessors) {
// 目標對象 Class 類型
final Class<?> targetType = contextObject != null ? contextObject.getClass() : null;
final List<PropertyAccessor> specificAccessors = new ArrayList<>();
final List<PropertyAccessor> generalAccessors = new ArrayList<>();
for (final PropertyAccessor resolver : propertyAccessors) {
// 讀取屬性訪問器能訪問的上下文類型
final Class<?>[] targets = resolver.getSpecificTargetClasses();
if (targets == null) {
// 通用訪問器能訪問任何類型
generalAccessors.add(resolver);
}
else if (targetType != null) {
for (final Class<?> clazz : targets) {
// 屬性訪問器能訪問的上下文類型列表中包含 contextObject
if (clazz == targetType) {
specificAccessors.add(resolver);
break;
}
// targetType 是當前類型的子類型
else if (clazz.isAssignableFrom(targetType)) {
generalAccessors.add(resolver);
}
}
}
}
final List<PropertyAccessor> resolvers = new ArrayList<>(specificAccessors);
generalAccessors.removeAll(specificAccessors);
resolvers.addAll(generalAccessors);
// 返回屬性訪問器列表
return resolvers;
}
private static class AccessorLValue implements ValueRef {
/**
* 屬性或字段引用
*/
private final PropertyOrFieldReference ref;
/**
* 當前上限文對象
*/
private final TypedValue contextObject;
/**
* 計算上下文
*/
private final EvaluationContext evalContext;
private final boolean autoGrowNullReferences;
public AccessorLValue(PropertyOrFieldReference propertyOrFieldReference, TypedValue activeContextObject,
EvaluationContext evalContext, boolean autoGrowNullReferences) {
ref = propertyOrFieldReference;
contextObject = activeContextObject;
this.evalContext = evalContext;
this.autoGrowNullReferences = autoGrowNullReferences;
}
@Override
public TypedValue getValue() {
// 計算值
final TypedValue value =
ref.getValueInternal(contextObject, evalContext, autoGrowNullReferences);
final PropertyAccessor accessorToUse = ref.cachedReadAccessor;
if (accessorToUse instanceof CompilablePropertyAccessor) {
ref.setExitTypeDescriptor(CodeFlow.toDescriptor(((CompilablePropertyAccessor) accessorToUse).getPropertyType()));
}
// 返回值
return value;
}
@Override
public void setValue(@Nullable Object newValue) {
ref.writeProperty(contextObject, evalContext, ref.name, newValue);
}
@Override
public boolean isWritable() {
return ref.isWritableProperty(ref.name, contextObject, evalContext);
}
}
}
表達式的 token 分類
SPEL 表達式特殊字符
enum TokenKind {
// 根據優先級排序,運算對象優先
/**
* 10進制整形字面量
*/
LITERAL_INT,
/**
* 10進制長整形字面量
*/
LITERAL_LONG,
/**
* 8進制整形字面量
*/
LITERAL_HEXINT,
/**
* 8進制長整形字面量
*/
LITERAL_HEXLONG,
/**
* 字符串字面量
*/
LITERAL_STRING,
/**
* 實數字面量
*/
LITERAL_REAL,
/**
* 浮點數字面量
*/
LITERAL_REAL_FLOAT,
/**
* 左括號
*/
LPAREN("("),
/**
* 右括號
*/
RPAREN(")"),
/**
* 逗號
*/
COMMA(","),
/**
* 標識符
*/
IDENTIFIER,
/**
* 分號
*/
COLON(":"),
/**
* 哈希
*/
HASH("#"),
/**
* 右方括號
*/
RSQUARE("]"),
/**
* 左方括號
*/
LSQUARE("["),
/**
* 左大括號
*/
LCURLY("{"),
/**
* 右大括號
*/
RCURLY("}"),
/**
* 點
*/
DOT("."),
/**
* 加
*/
PLUS("+"),
/**
* 乘
*/
STAR("*"),
/**
* 減
*/
MINUS("-"),
SELECT_FIRST("^["),
SELECT_LAST("$["),
QMARK("?"),
PROJECT("!["),
/**
* 除
*/
DIV("/"),
/**
* 大於等於
*/
GE(">="),
/**
* 大於
*/
GT(">"),
/**
* 小於等於
*/
LE("<="),
/**
* 小於
*/
LT("<"),
/**
* 等於
*/
EQ("=="),
/**
* 不等於
*/
NE("!="),
/**
* 求餘
*/
MOD("%"),
/**
* 取反
*/
NOT("!"),
/**
* 賦值
*/
ASSIGN("="),
/**
* instanceof
*/
INSTANCEOF("instanceof"),
/**
* 字符串的正則匹配
*/
MATCHES("matches"),
/**
* between
*/
BETWEEN("between"),
SELECT("?["),
/**
* 乘方
*/
POWER("^"),
ELVIS("?:"),
/**
* 安全導航
*/
SAFE_NAVI("?."),
/**
* bean 引用
*/
BEAN_REF("@"),
/**
* 工廠 bean 引用
*/
FACTORY_BEAN_REF("&"),
/**
* 或
*/
SYMBOLIC_OR("||"),
/**
* 與
*/
SYMBOLIC_AND("&&"),
/**
* 自增
*/
INC("++"),
/**
* 自減
*/
DEC("--");
final char[] tokenChars;
private final boolean hasPayload; // is there more to this token than simply the kind
private TokenKind(String tokenString) {
tokenChars = tokenString.toCharArray();
hasPayload = tokenChars.length == 0;
}
private TokenKind() {
this("");
}
@Override
public String toString() {
return name() + (tokenChars.length !=0 ? "(" + new String(tokenChars) +")" : "");
}
public boolean hasPayload() {
return hasPayload;
}
public int getLength() {
return tokenChars.length;
}
}
計算上下文
- org.springframework.expression.EvaluationContext:計算上下文
/**
* 計算上下文
*/
public interface EvaluationContext {
/**
* 返回默認的根對象
*/
TypedValue getRootObject();
/**
* 返回能讀取或寫入屬性的訪問器列表
*/
List<PropertyAccessor> getPropertyAccessors();
/**
* 返回定位構造函數的解析器列表
*/
List<ConstructorResolver> getConstructorResolvers();
/**
* 返回定位方法的解析器列表
*/
List<MethodResolver> getMethodResolvers();
/**
* 返回一個可以根據 Bean 名稱進行查找的 Bean 解析器
*/
@Nullable
BeanResolver getBeanResolver();
/**
* 返回一個類型定位器,可以根據短名稱或全限定名查找類型
*/
TypeLocator getTypeLocator();
/**
* 返回一個類型轉換器
*/
TypeConverter getTypeConverter();
/**
* 返回一個類型比較器
*/
TypeComparator getTypeComparator();
/**
* 返回可支持數學操作的 OperatorOverloader
*/
OperatorOverloader getOperatorOverloader();
/**
* 將此計算上下文中指定的變量名設置爲目標值
*/
void setVariable(String name, @Nullable Object value);
/**
* 在此計算上下文中查找命名對象
*/
@Nullable
Object lookupVariable(String name);
}
- org.springframework.expression.spel.support.StandardEvaluationContext:標準計算上下文
/**
* 一個強大的和高度可配置的計算上下文
*/
public class StandardEvaluationContext implements EvaluationContext {
/**
* 計算上下文的根對象
* 封裝了 org.springframework.beans.factory.config.BeanExpressionContext 實例
*/
private TypedValue rootObject;
/**
* 屬性訪問器列表
*/
@Nullable
private volatile List<PropertyAccessor> propertyAccessors;
/**
* 構造函數解析器列表
*/
@Nullable
private volatile List<ConstructorResolver> constructorResolvers;
/**
* 方法解析器列表
*/
@Nullable
private volatile List<MethodResolver> methodResolvers;
/**
* 基於反射的方法解析器
*/
@Nullable
private volatile ReflectiveMethodResolver reflectiveMethodResolver;
/**
* bean 解析器
*/
@Nullable
private BeanResolver beanResolver;
/**
* 類型定位器
*/
@Nullable
private TypeLocator typeLocator;
/**
* 類型轉換器
*/
@Nullable
private TypeConverter typeConverter;
/**
* 類型比較器
*/
private TypeComparator typeComparator = new StandardTypeComparator();
/**
* 操作符重載
*/
private OperatorOverloader operatorOverloader = new StandardOperatorOverloader();
/**
* 變量映射
*/
private final Map<String, Object> variables = new ConcurrentHashMap<>();
/**
* Create a {@code StandardEvaluationContext} with a null root object.
*/
public StandardEvaluationContext() {
rootObject = TypedValue.NULL;
}
@Override
public List<PropertyAccessor> getPropertyAccessors() {
return initPropertyAccessors();
}
private List<PropertyAccessor> initPropertyAccessors() {
List<PropertyAccessor> accessors = propertyAccessors;
if (accessors == null) {
accessors = new ArrayList<>(5);
accessors.add(new ReflectivePropertyAccessor());
propertyAccessors = accessors;
}
return accessors;
}
@Override
public List<ConstructorResolver> getConstructorResolvers() {
return initConstructorResolvers();
}
private List<ConstructorResolver> initConstructorResolvers() {
List<ConstructorResolver> resolvers = constructorResolvers;
if (resolvers == null) {
resolvers = new ArrayList<>(1);
resolvers.add(new ReflectiveConstructorResolver());
constructorResolvers = resolvers;
}
return resolvers;
}
@Override
public List<MethodResolver> getMethodResolvers() {
return initMethodResolvers();
}
private List<MethodResolver> initMethodResolvers() {
List<MethodResolver> resolvers = methodResolvers;
if (resolvers == null) {
resolvers = new ArrayList<>(1);
reflectiveMethodResolver = new ReflectiveMethodResolver();
resolvers.add(reflectiveMethodResolver);
methodResolvers = resolvers;
}
return resolvers;
}
@Override
@Nullable
public BeanResolver getBeanResolver() {
return beanResolver;
}
@Override
public TypeLocator getTypeLocator() {
if (typeLocator == null) {
typeLocator = new StandardTypeLocator();
}
return typeLocator;
}
@Override
public TypeConverter getTypeConverter() {
if (typeConverter == null) {
typeConverter = new StandardTypeConverter();
}
return typeConverter;
}
}
屬性訪問器
- org.springframework.expression.PropertyAccessor:屬性訪問器
/**
* 用於讀寫對象屬性的屬性訪問器
*/
public interface PropertyAccessor {
/**
* 返回目標對象的類型數組
*/
@Nullable
Class<?>[] getSpecificTargetClasses();
/**
* 目標對象 target 名稱爲 name 的屬性是否可以讀取
* @param context 計算上下文
* @param target 目標對象
* @param name 屬性名稱
*/
boolean canRead(EvaluationContext context, @Nullable Object target, String name) throws AccessException;
/**
* 從目標對象 target 上讀取名稱爲 name 的屬性的值
*/
TypedValue read(EvaluationContext context, @Nullable Object target, String name) throws AccessException;
/**
* 目標對象 target 名稱爲 name 的屬性是否可以寫入
*/
boolean canWrite(EvaluationContext context, @Nullable Object target, String name) throws AccessException;
/**
* 將新值 newValue 寫入目標對象 target 名稱爲 name 屬性中
*/
void write(EvaluationContext context, @Nullable Object target, String name, @Nullable Object newValue)
throws AccessException;
}
- org.springframework.context.expression.BeanExpressionContextAccessor:用於讀取 BeanExpressionContext【DefaultListableBeanFactory】中指定名稱的 bean
/**
* SPEL 屬性訪問器,用於訪問 BeanExpressionContext 計算上下文中指定的對象或屬性
*/
public class BeanExpressionContextAccessor implements PropertyAccessor {
/**
* BeanExpressionContext【DefaultListableBeanFactory】中是否包含指定名稱的 bean
*/
@Override
public boolean canRead(EvaluationContext context, @Nullable Object target, String name) throws AccessException {
return target instanceof BeanExpressionContext && ((BeanExpressionContext) target).containsObject(name);
}
/**
* 讀取 BeanExpressionContext【DefaultListableBeanFactory】中指定名稱的 bean
*/
@Override
public TypedValue read(EvaluationContext context, @Nullable Object target, String name) throws AccessException {
Assert.state(target instanceof BeanExpressionContext, "Target must be of type BeanExpressionContext");
return new TypedValue(((BeanExpressionContext) target).getObject(name));
}
/**
* 不允許寫入
*/
@Override
public boolean canWrite(EvaluationContext context, @Nullable Object target, String name) throws AccessException {
return false;
}
@Override
public void write(EvaluationContext context, @Nullable Object target, String name, @Nullable Object newValue)
throws AccessException {
throw new AccessException("Beans in a BeanFactory are read-only");
}
/**
* 屬性源對象類型
*/
@Override
public Class<?>[] getSpecificTargetClasses() {
return new Class<?>[] {BeanExpressionContext.class};
}
}
- org.springframework.expression.spel.support.ReflectivePropertyAccessor:基於反射方式讀寫對象屬性的訪問器
/**
* 基於反射方式讀寫對象屬性的訪問器
*/
public class ReflectivePropertyAccessor implements PropertyAccessor {
private static final Set<Class<?>> ANY_TYPES = Collections.emptySet();
private static final Set<Class<?>> BOOLEAN_TYPES;
static {
final Set<Class<?>> booleanTypes = new HashSet<>(4);
booleanTypes.add(Boolean.class);
booleanTypes.add(Boolean.TYPE);
BOOLEAN_TYPES = Collections.unmodifiableSet(booleanTypes);
}
/**
* 是否允許寫
*/
private final boolean allowWrite;
/**
* 讀操作緩存
*/
private final Map<PropertyCacheKey, InvokerPair> readerCache = new ConcurrentHashMap<>(64);
/**
* 寫操作緩衝
*/
private final Map<PropertyCacheKey, Member> writerCache = new ConcurrentHashMap<>(64);
/**
* 類型描述緩存
*/
private final Map<PropertyCacheKey, TypeDescriptor> typeDescriptorCache = new ConcurrentHashMap<>(64);
/**
* 已排序方法緩存
*/
private final Map<Class<?>, Method[]> sortedMethodsCache = new ConcurrentHashMap<>(64);
/**
* 上次執行操作的 InvokerPair
*/
@Nullable
private volatile InvokerPair lastReadInvokerPair;
@Override
public boolean canRead(EvaluationContext context, @Nullable Object target, String name) throws AccessException {
if (target == null) {
return false;
}
// 讀取對象類型
final Class<?> type = target instanceof Class ? (Class<?>) target : target.getClass();
// 讀取屬性的長度
if (type.isArray() && name.equals("length")) {
return true;
}
// 創建緩存鍵,如果已經在緩存中則直接返回
final PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class);
if (readerCache.containsKey(cacheKey)) {
return true;
}
// 查找指定屬性的標準 get 方法
final Method method = findGetterForProperty(name, type, target);
if (method != null) {
// 創建 Property 和 TypeDescriptor 並加入緩存中
final Property property = new Property(type, method, null);
final TypeDescriptor typeDescriptor = new TypeDescriptor(property);
// 寫入方法緩存
readerCache.put(cacheKey, new InvokerPair(method, typeDescriptor));
// 寫入類型描述符緩存
typeDescriptorCache.put(cacheKey, typeDescriptor);
return true;
}
else {
// 嘗試讀取屬性
final Field field = findField(name, type, target);
if (field != null) {
final TypeDescriptor typeDescriptor = new TypeDescriptor(field);
// 寫入屬性緩存
readerCache.put(cacheKey, new InvokerPair(field, typeDescriptor));
// 寫入類型描述符緩存
typeDescriptorCache.put(cacheKey, typeDescriptor);
return true;
}
}
return false;
}
/**
* 嘗試讀取標準的 get/is 方法
* @param propertyName 屬性名稱
* @param clazz 目標對象 Class
* @param target 目標對象
* @return
*/
@Nullable
private Method findGetterForProperty(String propertyName, Class<?> clazz, Object target) {
Method method = findGetterForProperty(propertyName, clazz, target instanceof Class);
if (method == null && target instanceof Class) {
method = findGetterForProperty(propertyName, target.getClass(), false);
}
return method;
}
/**
* Find a getter method for the specified property.
*/
@Nullable
protected Method findGetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) {
// 嘗試查找標準 get 方法
Method method = findMethodForProperty(getPropertyMethodSuffixes(propertyName),
"get", clazz, mustBeStatic, 0, ANY_TYPES);
if (method == null) {
// 嘗試查找標準 is 方法
method = findMethodForProperty(getPropertyMethodSuffixes(propertyName),
"is", clazz, mustBeStatic, 0, BOOLEAN_TYPES);
}
return method;
}
/**
* @param methodSuffixes 方法名稱後綴數組
* @param prefix 方法名稱前綴
* @param clazz 目標對象類型
* @param mustBeStatic 是否必須是靜態方法
* @param numberOfParams 目標方法參數個數
* @param requiredReturnTypes 目標方法返回值類型
* @return
*/
@Nullable
private Method findMethodForProperty(String[] methodSuffixes, String prefix, Class<?> clazz,
boolean mustBeStatic, int numberOfParams, Set<Class<?>> requiredReturnTypes) {
// 讀取所有的 public 方法
final Method[] methods = getSortedMethods(clazz);
for (final String methodSuffix : methodSuffixes) {
for (final Method method : methods) {
/**
* 方法名稱一致
* && 參數個數一致
* && 查找的是靜態方法,則當前方法的方法修飾符必須包含 static
* && 如果指定的 requiredReturnTypes 不爲空,則此方法的返回值必須在 requiredReturnTypes 中
*/
if (isCandidateForProperty(method, clazz)
&& method.getName().equals(prefix + methodSuffix)
&& method.getParameterCount() == numberOfParams
&&(!mustBeStatic || Modifier.isStatic(method.getModifiers())) &&
(requiredReturnTypes.isEmpty() ||
requiredReturnTypes.contains(method.getReturnType()))) {
return method;
}
}
}
return null;
}
/**
* Return class methods ordered with non-bridge methods appearing higher.
*/
private Method[] getSortedMethods(Class<?> clazz) {
return sortedMethodsCache.computeIfAbsent(clazz, key -> {
// 讀取所有的 public 方法
final Method[] methods = key.getMethods();
Arrays.sort(methods, (o1, o2) -> (o1.isBridge() == o2.isBridge() ? 0 : o1.isBridge() ? 1 : -1));
return methods;
});
}
protected boolean isCandidateForProperty(Method method, Class<?> targetClass) {
return true;
}
@Override
public TypedValue read(EvaluationContext context, @Nullable Object target, String name) throws AccessException {
Assert.state(target != null, "Target must not be null");
final Class<?> type = target instanceof Class ? (Class<?>) target : target.getClass();
if (type.isArray() && name.equals("length")) {
if (target instanceof Class) {
throw new AccessException("Cannot access length on array class itself");
}
// 讀取數組的長度
return new TypedValue(Array.getLength(target));
}
// 從緩存中讀取
final PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class);
InvokerPair invoker = readerCache.get(cacheKey);
lastReadInvokerPair = invoker;
// 1)如果是方法緩存
if (invoker == null || invoker.member instanceof Method) {
Method method = (Method) (invoker != null ? invoker.member : null);
if (method == null) {
method = findGetterForProperty(name, type, target);
if (method != null) {
// Treat it like a property...
// The readerCache will only contain gettable properties (let's not worry about setters for now).
final Property property = new Property(type, method, null);
final TypeDescriptor typeDescriptor = new TypeDescriptor(property);
invoker = new InvokerPair(method, typeDescriptor);
lastReadInvokerPair = invoker;
readerCache.put(cacheKey, invoker);
}
}
if (method != null) {
try {
// 設置訪問標識
ReflectionUtils.makeAccessible(method);
// 通過反射的方式讀取值
final Object value = method.invoke(target);
return new TypedValue(value, invoker.typeDescriptor.narrow(value));
}
catch (final Exception ex) {
throw new AccessException("Unable to access property '" + name + "' through getter method", ex);
}
}
}
// 如果是屬性緩存
if (invoker == null || invoker.member instanceof Field) {
Field field = (Field) (invoker == null ? null : invoker.member);
if (field == null) {
field = findField(name, type, target);
if (field != null) {
invoker = new InvokerPair(field, new TypeDescriptor(field));
lastReadInvokerPair = invoker;
readerCache.put(cacheKey, invoker);
}
}
if (field != null) {
try {
// 設置訪問標識
ReflectionUtils.makeAccessible(field);
// 讀取值
final Object value = field.get(target);
return new TypedValue(value, invoker.typeDescriptor.narrow(value));
}
catch (final Exception ex) {
throw new AccessException("Unable to access field '" + name + "'", ex);
}
}
}
throw new AccessException("Neither getter method nor field found for property '" + name + "'");
}
private static final class PropertyCacheKey implements Comparable<PropertyCacheKey> {
/**
* 目標對象類型
*/
private final Class<?> clazz;
/**
* 屬性名稱
*/
private final String property;
/**
* 目標對象是否是 Class
*/
private final boolean targetIsClass;
}
private static class InvokerPair {
/**
* 反射調用成員(Method 或 Field)
*/
final Member member;
/**
* 調用的返回值類型描述符
*/
final TypeDescriptor typeDescriptor;
public InvokerPair(Member member, TypeDescriptor typeDescriptor) {
this.member = member;
this.typeDescriptor = typeDescriptor;
}
}
}
/**
* 封裝了一個對象和描述該對象類型的描述符
*/
public class TypedValue {
/**
* {@link TypedValue} for {@code null}.
*/
public static final TypedValue NULL = new TypedValue(null);
/**
* 目標對象
*/
@Nullable
private final Object value;
/**
* 類型描述符
*/
@Nullable
private TypeDescriptor typeDescriptor;
}