如何通过Spring提供的EL表达式执行bean的属性或方法?

时间:2024-04-09 08:28:46

如何通过Spring提供的EL表达式执行bean的属性或方法?

关键两个bean:

org.springframework.expression.Expression

org.springframework.expression.spel.support.StandardEvaluationContext

实例:

import cn.hutool.extra.spring.SpringUtil;
import org.springframework.beans.factory.BeanExpressionException;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.context.expression.*;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.StandardTypeConverter;
import org.springframework.expression.spel.support.StandardTypeLocator;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestScope;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public final class CustomSpringBeanExpressionEvaluator {

    private final Map<String, Expression> expressionCache = new ConcurrentHashMap<>(256);

    private final Map<BeanExpressionContext, StandardEvaluationContext> evaluationCache = new ConcurrentHashMap<>(8);

    private final ExpressionParser parser = new SpelExpressionParser();

    private BeanExpressionContext beanExpressionContext;

    public static Object evaluate(@NonNull String expression) {
        return SpringUtil.getBean(CustomSpringBeanExpressionEvaluator.class).doEvaluate(expression);
    }

    /**
     * SpringEL表达式解析
     *
     * @param expression - EL表达式
     */
    public Object doEvaluate(@NonNull String expression) {
        if (!StringUtils.hasLength(expression)) {
            return expression;
        }
        try {
            Expression expr = this.expressionCache.get(expression);
            if (expr == null) {
                expr = this.parser.parseExpression(expression, this.beanExpressionParserContext);
                this.expressionCache.put(expression, expr);
            }
            if (this.beanExpressionContext == null) {
                this.beanExpressionContext = new BeanExpressionContext(SpringUtil.getConfigurableBeanFactory(), new RequestScope());
            }
            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());
                }));
                this.evaluationCache.put(beanExpressionContext, sec);
            }
            return expr.getValue(sec);
        } catch (Throwable ex) {
            throw new BeanExpressionException("Expression parsing failed", ex);
        }
    }

    private final ParserContext beanExpressionParserContext = new ParserContext() {
        @Override
        public boolean isTemplate() {
            return true;
        }

        @Override
        public String getExpressionPrefix() {
            return "#{";
        }

        @Override
        public String getExpressionSuffix() {
            return "}";
        }
    };
}

使用示例

CustomSpringBeanExpressionEvaluator.evaluate("#{bean.fieldName}")

CustomSpringBeanExpressionEvaluator.evaluate("#{bean.methodName}")