Spring中Map<String, DataTablesRepository>键不符合预期问题求助
问题:Spring Service中手动初始化的Repository映射Map键不符合预期
问题描述
尝试在Spring的@Service类中定义一个Map<String, DataTablesRepository>来映射多个JPA Repository,代码如下:
@Service @AllArgsConstructor public class MyDataTablesService { private final RegistroDtRepository registroDtRepository; private final ContinentiDtRepository continentiDtRepository; public Map<String, DataTablesRepository> repositories = this.createMap(); public DataTablesOutput<?> findAllDatatable(String repoId, DataTablesInput input) { System.out.println(this.repositories); DataTablesRepository repository = this.repositories.get(repoId); DataTablesOutput<?> res = repository.findAll(input); return res; } private Map<String, DataTablesRepository> createMap(){ Map<String, DataTablesRepository> myMap = new HashMap<String, DataTablesRepository>(); myMap.put("continenti", this.continentiDtRepository); myMap.put("registro", this.registroDtRepository); return myMap; } }
调用findAllDatatable方法时,预期控制台输出的Map键为自定义的"registro"和"continenti":
{registro=org.springframework.data.jpa.datatables.repository.DataTablesRepositoryImpl@2aec0c10, continenti=org.springframework.data.jpa.datatables.repository.DataTablesRepositoryImpl@1bf71fb7}
但实际输出的键却是成员变量名:
{registroDtRepository=org.springframework.data.jpa.datatables.repository.DataTablesRepositoryImpl@2aec0c10, continentiDtRepository=org.springframework.data.jpa.datatables.repository.DataTablesRepositoryImpl@1bf71fb7}
导致通过this.repositories.get("continenti")获取Repository时返回null。
问题原因
Spring有自动注入集合类型依赖的特性:当容器中存在Map<String, T>类型的成员变量时,Spring会自动收集所有类型为T的Bean,并以Bean的名称(这里就是你声明的成员变量名registroDtRepository、continentiDtRepository)作为键,填充到这个Map中。
你在成员变量声明时手动初始化的repositories被Spring的自动注入行为覆盖了,最终使用的是Spring自动生成的Map,而非你自定义的Map。
解决方法
方法1:使用@PostConstruct初始化Map
利用Spring的生命周期注解@PostConstruct,确保在所有依赖注入完成后再初始化自定义Map:
@Service @AllArgsConstructor public class MyDataTablesService { private final RegistroDtRepository registroDtRepository; private final ContinentiDtRepository continentiDtRepository; private Map<String, DataTablesRepository> repositories; @PostConstruct private void initRepositoryMap() { repositories = new HashMap<>(); repositories.put("continenti", continentiDtRepository); repositories.put("registro", registroDtRepository); } public DataTablesOutput<?> findAllDatatable(String repoId, DataTablesInput input) { System.out.println(this.repositories); DataTablesRepository repository = this.repositories.get(repoId); return repository.findAll(input); } }
方法2:在构造函数中初始化Map
通过构造函数直接初始化Map,避免Spring自动注入的干扰:
@Service public class MyDataTablesService { private final RegistroDtRepository registroDtRepository; private final ContinentiDtRepository continentiDtRepository; private final Map<String, DataTablesRepository> repositories; // 手动编写构造函数,替换Lombok的@AllArgsConstructor public MyDataTablesService(RegistroDtRepository registroDtRepository, ContinentiDtRepository continentiDtRepository) { this.registroDtRepository = registroDtRepository; this.continentiDtRepository = continentiDtRepository; this.repositories = new HashMap<>(); this.repositories.put("continenti", continentiDtRepository); this.repositories.put("registro", registroDtRepository); } public DataTablesOutput<?> findAllDatatable(String repoId, DataTablesInput input) { System.out.println(this.repositories); DataTablesRepository repository = this.repositories.get(repoId); return repository.findAll(input); } }
关键说明
- 将
repositories改为private可以降低Spring自动注入的优先级,避免被自动填充; @PostConstruct是Spring官方推荐的初始化方式,确保依赖完全注入后再执行自定义逻辑,是最稳妥的方案。
内容的提问来源于stack exchange,提问作者user2880516
相关产品推荐
相关产品推荐

