Spring 1.5.2连接双MongoDB异常:仅用单一连接的问题求助
解决Spring 1.5.2多MongoDB连接配置冲突问题
看起来你在Spring 1.5.2版本中配置双MongoDB连接时遇到了bean覆盖的问题——要么所有Repository都用主连接,要么全部用内部连接。这主要是因为AbstractMongoConfiguration的自动bean注册逻辑和你自定义的配置产生了冲突,加上缺少了每个连接对应的独立映射上下文,导致实体和Repository无法正确绑定。
下面是具体的调整方案:
1. 重构BaseMongoConfig,避免自动创建默认bean
原有的BaseMongoConfig继承了AbstractMongoConfiguration,这个父类会自动注册一个无名称的默认mongoTemplate bean,这会和你自定义的带名称的mongoTemplate产生覆盖冲突。我们需要重构基类,只保留工具方法,不再继承AbstractMongoConfiguration:
@ConfigurationProperties public abstract class BaseMongoConfig { // 注入的配置属性 private String host; private int port; private String database; private String username; private String password; private String authenticationDatabase; // 生成getter和setter方法 // 创建MongoClient的工具方法 protected MongoClient getMongoClient() { MongoCredential credential = MongoCredential.createCredential( username, authenticationDatabase != null ? authenticationDatabase : database, password.toCharArray() ); return new MongoClient(new ServerAddress(host, port), Arrays.asList(credential)); } // 创建SimpleMongoDbFactory的工具方法 protected SimpleMongoDbFactory getMongoDbFactory() { return new SimpleMongoDbFactory(getMongoClient(), database); } // 让子类实现各自的MongoMappingContext(关键:每个连接对应独立的实体映射) protected abstract MongoMappingContext mongoMappingContext() throws ClassNotFoundException; }
2. 调整主连接配置类(CustomerDataMongoConnection)
需要明确指定该连接对应的MongoMappingContext(绑定customer域的实体),并排除Spring的自动Mongo配置,避免冲突:
@Primary @Configuration @EnableMongoRepositories( basePackages = "backend.repository.customer", mongoTemplateRef = CustomerDataMongoConnection.TEMPLATE_NAME, mappingContextRef = CustomerDataMongoConnection.MAPPING_CONTEXT_NAME // 绑定专属映射上下文 ) @ConfigurationProperties(prefix = "customer.mongodb") @EnableAutoConfiguration(exclude = MongoAutoConfiguration.class) // 排除自动配置 public class CustomerDataMongoConnection extends BaseMongoConfig { public static final String TEMPLATE_NAME = "customerDataMongoTemplate"; public static final String MAPPING_CONTEXT_NAME = "customerMongoMappingContext"; // 配置专属的MongoMappingContext,只扫描customer域的实体 @Bean(name = MAPPING_CONTEXT_NAME) public MongoMappingContext customerMongoMappingContext() throws ClassNotFoundException { MongoMappingContext mappingContext = new MongoMappingContext(); mappingContext.setInitialEntitySet( new EntityScanner(getClass().getClassLoader()).scan("backend.domain.customer") ); return mappingContext; } @Bean(name = TEMPLATE_NAME) public MongoTemplate mongoTemplate() throws ClassNotFoundException { // 绑定专属的DbFactory和MappingContext return new MongoTemplate(getMongoDbFactory(), mongoMappingContext()); } }
3. 调整内部连接配置类(InternalDataMongoConnection)
同样给内部连接配置专属的MongoMappingContext,绑定internal域的实体:
@Configuration @EnableMongoRepositories( basePackages = "backend.repository.internal", mongoTemplateRef = InternalDataMongoConnection.TEMPLATE_NAME, mappingContextRef = InternalDataMongoConnection.MAPPING_CONTEXT_NAME ) @ConfigurationProperties(prefix = "internal.mongodb") public class InternalDataMongoConnection extends BaseMongoConfig { public static final String TEMPLATE_NAME = "internalDataMongoTemplate"; public static final String MAPPING_CONTEXT_NAME = "internalMongoMappingContext"; @Bean(name = MAPPING_CONTEXT_NAME) public MongoMappingContext internalMongoMappingContext() throws ClassNotFoundException { MongoMappingContext mappingContext = new MongoMappingContext(); mappingContext.setInitialEntitySet( new EntityScanner(getClass().getClassLoader()).scan("backend.domain.internal") ); return mappingContext; } @Bean(name = TEMPLATE_NAME) public MongoTemplate mongoTemplate() throws ClassNotFoundException { return new MongoTemplate(getMongoDbFactory(), mongoMappingContext()); } }
关键调整说明
- 移除@EntityScan:这个注解是给JPA用的,对MongoDB无效,我们通过
MongoMappingContext的setInitialEntitySet方法扫描指定包下的@Document实体。 - 独立MongoMappingContext:每个MongoDB连接需要自己的映射上下文,这样不同库的实体不会被混淆,Repository才能正确绑定到对应的数据库。
- 排除自动配置:主连接配置类加上
@EnableAutoConfiguration(exclude = MongoAutoConfiguration.class),防止Spring自动创建默认的Mongo相关bean干扰自定义配置。 - 明确bean名称:所有的MongoTemplate和MongoMappingContext都指定唯一的bean名称,避免Spring的自动装配逻辑出错。
验证配置
你可以在Service层注入对应的Repository,然后通过日志打印MongoTemplate的数据库名称来验证:
@Service public class ContactHistoryService { private final ContactHistoryRepository repository; private final MongoTemplate customerMongoTemplate; public ContactHistoryService(ContactHistoryRepository repository, @Qualifier("customerDataMongoTemplate") MongoTemplate customerMongoTemplate) { this.repository = repository; this.customerMongoTemplate = customerMongoTemplate; // 打印当前连接的数据库名称 System.out.println("Customer DB Name: " + customerMongoTemplate.getDb().getName()); } }
内容的提问来源于stack exchange,提问作者Tobias
相关产品推荐
相关产品推荐

