Spring Data Elasticsearch中@Mapping与@Setting路径SpEL无法解析怎么办
当前Spring Data Elasticsearch仅对@Document注解的相关属性内置了SpEL解析能力,@Setting、@Mapping注解的路径属性默认没有做SpEL解析处理,所以表达式会被当成普通资源路径读取,才会抛出找不到资源的报错。
通过自定义Elasticsearch持久化实体和映射上下文,手动添加SpEL解析逻辑即可实现需求,具体实现步骤如下:
1. 自定义支持SpEL解析的持久化实体
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty; import org.springframework.data.util.TypeInformation; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class SpelSupportedElasticsearchPersistentEntity<T> extends SimpleElasticsearchPersistentEntity<T> implements ApplicationContextAware { private static final SpelExpressionParser PARSER = new SpelExpressionParser(); private ApplicationContext applicationContext; private StandardEvaluationContext evaluationContext; public SpelSupportedElasticsearchPersistentEntity(TypeInformation<T> information) { super(information); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; this.evaluationContext = new StandardEvaluationContext(); evaluationContext.setBeanResolver((context, beanName) -> applicationContext.getBean(beanName)); } @Override public String getSettingPath() { String originalPath = super.getSettingPath(); return parseSpelIfNecessary(originalPath); } @Override public String getMappingPath() { String originalPath = super.getMappingPath(); return parseSpelIfNecessary(originalPath); } private String parseSpelIfNecessary(String value) { if (value != null && value.startsWith("#{")) { return PARSER.parseExpression(value).getValue(evaluationContext, String.class); } return value; } }
2. 自定义映射上下文,替换默认实体创建逻辑
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty; import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext; import org.springframework.data.util.TypeInformation; public class SpelSupportedElasticsearchMappingContext extends SimpleElasticsearchMappingContext { @Override protected <T> ElasticsearchPersistentEntity<T> createPersistentEntity(TypeInformation<T> typeInformation) { SpelSupportedElasticsearchPersistentEntity<T> entity = new SpelSupportedElasticsearchPersistentEntity<>(typeInformation); entity.setApplicationContext(getApplicationContext()); return entity; } }
3. 注册自定义映射上下文到Spring容器
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchMappingContext; @Configuration public class ElasticsearchConfig { @Bean public ElasticsearchMappingContext elasticsearchMappingContext() { return new SpelSupportedElasticsearchMappingContext(); } // 保留你原有配置Bean即可 @Bean public String mySettingsFilePath() { return "classpath:index-settings.json"; } }
注意事项
- 该实现同时支持@Setting的
settingPath和@Mapping的mappingPath属性的SpEL解析,用法和@Document注解中的SpEL用法完全一致 - 如果SpEL表达式中引用了其他Bean,需要确保对应Bean的初始化顺序早于ElasticsearchMappingContext,避免解析时找不到Bean
- 该实现兼容Spring Data Elasticsearch 4.0+所有版本,低版本调整对应方法名即可使用
内容的提问来源于stack exchange,提问作者Андрей Палкин
相关产品推荐
相关产品推荐

