You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

运行时修改SolrDocument注解后查询仍用旧集合名问题求助

问题描述

我正在使用Spring Data Solr,定义了如下Solr文档模型类TestDocument和对应的SolrCrudRepository:

@SolrDocument(collection = "oldCollectionName") 
public class TestDocument { 
    @Id @Indexed(name = "id", type = "string") 
    private String id; 
    @Field(value = "name") 
    private String name; 
    @Field(value = "externalid") 
    private Integer externalId; 
}

我想在运行时修改该类上的@SolrDocument(collection = "oldCollectionName")注解值,于是写了Service方法,通过反射修改注解后日志显示注解已设为新集合名,但调用testDocumentRepository的查询方法时,仍使用旧集合名。

Service方法代码:

public List<TestDocument> getDocumentsByName(String name){ 
    String newSolrDocument = getModifiedSolrCollectionName(); 
    alterAnnotationValue(TestDocument.class, SolrDocument.class, newSolrDocument); 
    SolrDocument solrDocument = TestDocument.class.getAnnotation(SolrDocument.class); 
    LOGGER.info("Dynamically set SolrDocument Annotaation: "+solrDocument.collection()); 
    return testDocumentRepository.findByName(name); 
}

修改注解的工具方法:

public void alterAnnotationValue(Class<?> targetClass, Class<? extends Annotation> targetAnnotation, String newCollectionName) { 
    try { 
        Method method = Class.class.getDeclaredMethod("getAnnotationData", null); 
        method.setAccessible(true); 
        Object annotationData = method.invoke(targetClass); 
        Field annotations = annotationData.getClass().getDeclaredField("annotations"); 
        annotations.setAccessible(true); 
        Map<Class<? extends Annotation>, Annotation> map = (Map<Class<? extends Annotation>, Annotation>) annotations.get(annotationData); 
        // 重新创建SolrDocument注解实例
        SolrDocument newAnnotation = new SolrDocument() {
            @Override
            public Class<? extends Annotation> annotationType() {
                return SolrDocument.class;
            }

            @Override
            public String collection() {
                return newCollectionName;
            }

            @Override
            public String solrCore() {
                return ""; // 保留原注解默认值或按需设置
            }
        };
        map.put(targetAnnotation, newAnnotation); 
    } catch (Exception e) { 
        e.printStackTrace(); 
    } 
}

(注:修正了原工具方法中参数类型不匹配的问题,需创建有效的注解实例而非直接传入字符串)

现在的问题是:反射修改类注解后,Repository查询仍使用旧集合名,请问还需做什么才能让修改生效?

问题分析与解决方案

嘿,这个坑我之前也踩过——你遇到的是Spring Data框架的初始化缓存机制在搞鬼!

为什么反射修改注解不生效?

Spring Data Solr在应用启动阶段,就已经扫描解析了@SolrDocument的注解信息,把集合名绑定到了SolrCrudRepository的实现类中,并且这个配置是被缓存起来的。你后续通过反射修改Class对象上的注解元数据,已经初始化好的Repository实例根本不会再去读取这个更新后的注解,所以查询还是会用旧的集合名。

可行的解决思路

你需要绕过Spring Data的静态缓存,动态指定集合名执行查询,这里给你三个实用方案:


方案1:直接用SolrTemplate动态指定集合名

SolrTemplate支持手动指定查询的集合,完全不依赖模型类上的注解,是最直接的解决方式:

@Autowired
private SolrTemplate solrTemplate;

public List<TestDocument> getDocumentsByName(String name){ 
    String newCollectionName = getModifiedSolrCollectionName(); 
    // 构造查询条件
    SolrQuery query = new SolrQuery("name:" + name);
    // 手动指定集合名执行查询
    return solrTemplate.queryForList(newCollectionName, query, TestDocument.class);
}

方案2:动态创建Repository实例

如果你还是想用Repository的自定义查询方法(比如findByName),可以通过SolrRepositoryFactory动态创建新的Repository实例,每次都指定最新的集合名:

@Autowired
private SolrClient solrClient;

public List<TestDocument> getDocumentsByName(String name){ 
    String newCollectionName = getModifiedSolrCollectionName(); 
    // 基于新集合名创建SolrTemplate
    SolrTemplate dynamicSolrTemplate = new SolrTemplate(solrClient, newCollectionName);
    // 动态生成Repository实例
    SolrRepositoryFactory factory = new SolrRepositoryFactory(dynamicSolrTemplate);
    TestDocumentRepository dynamicRepo = factory.getRepository(TestDocumentRepository.class);
    return dynamicRepo.findByName(name);
}

这种方式每次都会生成全新的Repository实例,完全避开了原有实例的缓存问题。


方案3:刷新Spring Bean上下文(不推荐)

如果非要让原有Repository实例生效,你需要触发Spring上下文刷新,重新初始化所有相关Bean,但这种方式会影响应用性能,还可能引发其他依赖问题,不建议在生产环境使用。

额外提醒

你原有的注解修改工具方法存在参数类型错误,注解是接口,必须通过匿名内部类实现所有方法才能创建有效的注解实例,我已经在代码中帮你修正了这一点。

内容的提问来源于stack exchange,提问作者user3388770

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:28:11