- Autowired等注解
- Value注解
- Lookup注解
evaluateBeanDefinitionString是doResolveDependency方法处理@Value注解的第三步,evaluateBeanDefinitionString解析@Value注解中设置value的SpEL表达式,将#{xxx}替换为BeanExpressionResolver解析出来的值。
回顾一下doResolveDependency方法,如下
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Class<?> type = descriptor.getDependencyType();
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
...
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
前面分析过,evaluateBeanDefinitionString将会调用到StandardBeanExpressionResolver#evaluate方法,从这个方法开始分析
public Object evaluate(@Nullable String value, BeanExpressionContext beanExpressionContext) throws BeansException {
if (!StringUtils.hasLength(value)) {
return value;
}
try {
Expression expr = this.expressionCache.get(value);
if (expr == null) {
expr = this.expressionParser.parseExpression(value, this.beanExpressionParserContext);
this.expressionCache.put(value, expr);
}
StandardEvaluationContext sec = this.evaluationCache.get(beanExpressionContext);
if (sec == null) {
sec = new StandardEvaluationContext(beanExpressionContext);
sec.addPropertyAccessor(new BeanExpressionContextAccessor());
sec.addPropertyAccessor(new BeanFactoryAccessor());
sec.addPropertyAccessor(new MapAccessor());
sec.addPropertyAccessor(new EnvironmentAccessor());
sec.setBeanResolver(new BeanFactoryResolver(beanExpressionContext.getBeanFactory()));
sec.setTypeLocator(new StandardTypeLocator(beanExpressionContext.getBeanFactory().getBeanClassLoader()));
sec.setTypeConverter(new StandardTypeConverter(() -> {
ConversionService cs = beanExpressionContext.getBeanFactory().getConversionService();
return (cs != null ? cs : DefaultConversionService.getSharedInstance());
}));
customizeEvaluationContext(sec);
this.evaluationCache.put(beanExpressionContext, sec);
}
return expr.getValue(sec);
}
catch (Throwable ex) {
throw new BeanExpressionException("Expression parsing failed", ex);
}
}
StandardBeanExpressionResolver#evaluate做了三件事情,
- 调用expressionParser解析出Expression
- 实例化了一个StandardEvaluationContext
- 返回Expression#getValue的结果
StandardEvaluationContext包装了与Spring交互的工具,不深入分析。看另外两个
- Expression解析
parseExpression方法的第二个参数beanExpressionParserContext就是一个匿名内部类实例化的对象,就是定义了模板的prefix和suffix,分别是#{和},isTemplate返回true
private final ParserContext beanExpressionParserContext = new ParserContext() {
@Override
public boolean isTemplate() {
return true;
}
@Override
public String getExpressionPrefix() {
return expressionPrefix;
}
@Override
public String getExpressionSuffix() {
return expressionSuffix;
}
};
parseExpression方法会调用到TemplateAwareExpressionParser#parseExpression方法,会进而调用parseTemplate方法
public Expression parseExpression(String expressionString, @Nullable ParserContext context) throws ParseException {
if (context != null && context.isTemplate()) {
return parseTemplate(expressionString, context);
}
else {
return doParseExpression(expressionString, context);
}
}
parseTemplate逻辑也比较简单,调用了parseExpressions
private Expression parseTemplate(String expressionString, ParserContext context) throws ParseException {
if (expressionString.isEmpty()) {
return new LiteralExpression("");
}
Expression[] expressions = parseExpressions(expressionString, context);
if (expressions.length == 1) {
return expressions[0];
}
else {
return new CompositeStringExpression(expressionString, expressions);
}
}
parseExpressions即将expressionString按prefix和suffix分割,对#{、}里面的内容调用doParseExpression方法解析成SpEL的语法树,不在深入分析。
private Expression[] parseExpressions(String expressionString, ParserContext context) throws ParseException {
List<Expression> expressions = new ArrayList<>();
String prefix = context.getExpressionPrefix();
String suffix = context.getExpressionSuffix();
int startIdx = 0;
while (startIdx < expressionString.length()) {
int prefixIndex = expressionString.indexOf(prefix, startIdx);
if (prefixIndex >= startIdx) {
// an inner expression was found - this is a composite
if (prefixIndex > startIdx) {
expressions.add(new LiteralExpression(expressionString.substring(startIdx, prefixIndex)));
}
int afterPrefixIndex = prefixIndex + prefix.length();
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 {
// no more ${expressions} found in string, add rest as static text
expressions.add(new LiteralExpression(expressionString.substring(startIdx)));
startIdx = expressionString.length();
}
}
return expressions.toArray(new Expression[0]);
}
- Expression#getValue
Expression有三个实现。LiteralExpression、SpelExpression、CompositeStringExpression。LiteralExpression和CompositeStringExpression的逻辑都很简单。
LiteralExpression就是字面量表达式,getValue方法直接返回这个字面量
public String getValue(@Nullable Object rootObject) {
return this.literalValue;
}
CompositeStringExpression组合多个Expression,getValue方法遍历所有Expression#getValue,拼接返回
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();
}
SpelExpression实现比较复杂,核心逻辑外就是调用了ast.getTypedValue方法
public <T> T getValue(@Nullable Class<T> expectedResultType) throws EvaluationException {
CompiledExpression compiledAst = this.compiledAst;
if (compiledAst != null) {
try {
EvaluationContext context = getEvaluationContext();
Object result = compiledAst.getValue(context.getRootObject().getValue(), context);
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.compiledAst = null;
this.interpretedCount.set(0);
}
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);
}
ast是前面解析SpelExpression生成的语法树,语法树的每个节点都是SpelNodeImpl。SpelNodeImpl代表SpEL支持的各种语法,有很多子类,例如:
- 字面量,IntLiteral、LongLiteral、NullLiteral等
- 比较操作,OpEQ、OpNE等
- 从beanFactory获取bean,BeanReference
- 数组、List、Map按索引取元素,Indexer
SpelNodeImpl一个比较重要的属性就是children,就是当前节点的孩子。
public abstract class SpelNodeImpl implements SpelNode, Opcodes {
protected SpelNodeImpl[] children = SpelNodeImpl.NO_CHILDREN;
}
例如表达式1 == 2解析成的语法树根节点为OpEQ,根节点有两个IntLiteral子节点,分别是1和2。
ast#getTypedValue进一步调用getValueInternal方法,getValueInternal在SpelNodeImpl各个子类去实现。看几个SpelNodeImpl的实现
1、OpEQ
OpEQ有两个children,分别对左Operand和右Operand求值,判断相等
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
Object left = getLeftOperand().getValueInternal(state).getValue();
Object right = getRightOperand().getValueInternal(state).getValue();
this.leftActualDescriptor = CodeFlow.toDescriptorFromObject(left);
this.rightActualDescriptor = CodeFlow.toDescriptorFromObject(right);
return BooleanTypedValue.forValue(equalityCheck(state.getEvaluationContext(), left, right));
}
2、BeanReference
获取到BeanResolver,通过beanResolver#resolve按name获取bean
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
BeanResolver beanResolver = state.getEvaluationContext().getBeanResolver();
if (beanResolver == null) {
throw new SpelEvaluationException(
getStartPosition(), SpelMessage.NO_BEAN_RESOLVER_REGISTERED, this.beanName);
}
try {
return new TypedValue(beanResolver.resolve(state.getEvaluationContext(), this.beanName));
}
catch (AccessException ex) {
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.EXCEPTION_DURING_BEAN_RESOLUTION,
this.beanName, ex.getMessage());
}
}
beanResolver就是BeanFactoryResolver,从beanFactory获取bean
public Object resolve(EvaluationContext context, String beanName) throws AccessException {
try {
return this.beanFactory.getBean(beanName);
}
catch (BeansException ex) {
throw new AccessException("Could not resolve bean reference against BeanFactory", ex);
}
}
所有支持的语法都在org.springframework.expression.spel.ast包下