-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
修改默认EL表达式解析 #485
base: master
Are you sure you want to change the base?
修改默认EL表达式解析 #485
Conversation
@DS("#{T(pkg.A).B()}")
报错`org.springframewo…
https://github.com/baomidou/dynamic-datasource-spring-boot-starter/blob/d0300b5bef1a056a94c9c4cbd1a552a18927f464/core/src/main/java/com/baomidou/dynamic/datasource/aop/DynamicDataSourceAnnotationInterceptor.java#L58 这样一来想正常使用EL表达式就必须写一个Bean处理,我认为挺多余的,又不是存在不符合默认约定的特殊处理逻辑一定要写Bean @Bean
public DsProcessor dsProcessor() {
DsHeaderProcessor dsHeaderProcessor = new DsHeaderProcessor();
DsSessionProcessor dsSessionProcessor = new DsSessionProcessor();
DsSpelExpressionProcessor dsSpelExpressionProcessor = new DsSpelExpressionProcessor();
dsSpelExpressionProcessor.setParserContext(ParserContext.TEMPLATE_EXPRESSION);
dsHeaderProcessor.setNextProcessor(dsSessionProcessor);
dsSessionProcessor.setNextProcessor(dsSpelExpressionProcessor);
return new DsProcessor() {
@Override
public boolean matches(String s) {
return false;
}
@Override
public String determineDatasource(MethodInvocation invocation, String key) {
return dsHeaderProcessor.determineDatasource(invocation, key);
}
@Override
public String doDetermineDatasource(MethodInvocation methodInvocation, String s) {
return null;
}
};
} |
#199 有点不太懂到底该怎么样 |
测试: public static void main(String[] args) {
String spel1 = "T(Integer).MAX_VALUE";
String spel2 = "new java.util.Date()";
ExpressionParser parser = new SpelExpressionParser();
// 这是你 DsSpelExpressionProcessor 里定义的
ParserContext parserContext = new ParserContext() {
@Override
public boolean isTemplate() {
return false;
}
@Override
public String getExpressionPrefix() {
return null;
}
@Override
public String getExpressionSuffix() {
return null;
}
};
// 但实际上根据 DynamicDataSourceAutoConfiguration 来看,匹配流程是
// 常量key --> #开头的key,而#开头的key匹配顺序是
// headerProcessor --> sessionProcessor --> spelExpressionProcessor
// 所以这时候的spel表达式必然是以#开头的key
// 所以有三种思路:
// 1, key写为 #SPEL,ParserContext 直接以 # 为 getExpressionPrefix 的返回值,
// 但是会抛异常 SpelEvaluationException: EL1006E: Function 'T' could not be found,所以这个思路pass掉
// 2, key写为 #{SPEL},即直接设计以 #{} 额外包裹SPEL表达式,这样直接使用 ParserContext.TEMPLATE_EXPRESSION 即可
// 3, key.substring(1),即手动裁剪掉#,然后用全 null 的 ParserContext
// 我这个pr倾向于思路2
// 思路3的流程
int result3 = parser.parseExpression(("#" + spel1).substring(1), parserContext).getValue(int.class);
System.out.println(result3 == Integer.MAX_VALUE);
Date result4 = parser.parseExpression(("#" + spel2).substring(1), parserContext).getValue(Date.class);
System.out.println(result4);
// 思路2的流程
parserContext = ParserContext.TEMPLATE_EXPRESSION;
int result1 = parser.parseExpression("#{" + spel1 + "}", parserContext).getValue(int.class);
System.out.println(result1 == Integer.MAX_VALUE);
Date result2 = parser.parseExpression("#{" + spel2 + "}", parserContext).getValue(Date.class);
System.out.println(result2);
// 思路1会报错
parserContext = new ParserContext() {
@Override
public boolean isTemplate() {
return false;
}
@Override
public String getExpressionPrefix() {
return "#";
}
@Override
public String getExpressionSuffix() {
return null;
}
};
try {
int result5 = parser.parseExpression(("#" + spel1), parserContext).getValue(int.class);
System.out.println(result5 == Integer.MAX_VALUE);
} catch (SpelEvaluationException e) {
e.printStackTrace();
}
try {
Date result6 = parser.parseExpression(("#" + spel2), parserContext).getValue(Date.class);
System.out.println(result6);
} catch (SpelEvaluationException e) {
e.printStackTrace();
}
} 输出:
|
#199 (comment) |
反正合并你这个不会影响绝大部分用户吧. 我其实不懂SPEL这么深0 0, 我一般就是#obg.name最多. |
但凡要用到SPEL表达式的,除了像你这样光调变量 覆盖后 你之前 |
57e3834
to
cd81af0
Compare
…expression.spel.SpelParseException: Expression [#{T(pkg.A).B()}] @1: EL1043E: Unexpected token. Expected 'identifier' but was 'lcurly({)'`
同时用 |
周末已经解决好冲突了 修改为TEMPLATE_EXPRESSION后,正确的用法包括不限于以下 |
嗯,我得考虑下 |
这个pr还考虑合并吗 |
如果用 DsSpelExpressionProcessor 使用 ParserContext.TEMPLATE_EXPRESSION 的话,在 org.springframework.expression.common.TemplateAwareExpressionParser.parseExpressions() 里会检查是否有前后缀,如果没有就把整体当做 spel 的结果输出了,后果就是 #param.field 这种用法就失效了。 |
其实还就是历史包袱拖累的问题,这个问题最早因为没有采用标准的SPEL表达式而产生,在数年前出现相关issue后没有及时查清SPEL的恰当用法,最终让一次改正的包袱变得沉重。。。 |
What kind of change does this PR introduce? (check at least one)
The description of the PR:
@DS("#{T(pkg.A).B()}")
报错org.springframework.expression.spel.SpelParseException: Expression [#{T(pkg.A).B()}] @1: EL1043E: Unexpected token. Expected 'identifier' but was 'lcurly({)'
,否则用EL表达式还得初始化BEAN也太没必要了Other information:
4ddfc4d