不同数据源冲突

在spring里面配置了两个以上数据源的时候,可能会出现报错,例如我配置了ES和Mongo两个数据源,就会这样:

1
The bean 'xxxxEsRepository', defined in xx.repositories.xxEsRepository defined in @EnableMongoRepositories declared on xxApplication, could not be registered. A bean with that name has already been defined in me.xxx.repositories.xxxEsRepository defined in @EnableElasticsearchRepositories declared on xxApplication and overriding is disabled.

一段报错里出现了@EnableMongoRepositories@EnableElasticsearchRepositories两个注解,意思就是Repository的bean冲突了。

由于我们的@EnableElasticsearchRepositories写在前面,所以所有标注了@@Repository的都被作为ES的repo注入了,接下来@EnableMongoRepositories还会再做同样的事情,每个bean都被注册了两次,就冲突了。

这个时候,就要我们手动来指定哪个配置对应哪个repo了,手动指定两个配置对应的repo就行了。

原来的@Enable注解修改一下:

1
2
3
4
5
6
7
8
9
10
11
// before
@EnableElasticsearchRepositories
@EnableMongoRepositories


// after
@EnableElasticsearchRepositories(
includeFilters = [ComponentScan.Filter(type = FilterType.REGEX, pattern = [".*EsRepository"])]
)
@EnableMongoRepositories(
includeFilters = [ComponentScan.Filter(type = FilterType.REGEX, pattern = [".*MongoRepository"])])

只要加一个includeFilters,指定你要用哪个repo的类就行了,当然,你也可以用excludeFilters排除不相干的类。这里用basePackageClasses没有用,暂时不知道为啥。

同一个数据源不同数据库

还有另外一种常见操作是,在同一个数据源里面我们要请求不同的数据库,或者不同服务器。这个时候还是类似上面的操作。

因为有两个Configuration,所以要注解两次,这时候优先使用Java配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@Configuration("primary")
@EnableMongoRepositories(basePackageClasses = [ChatMessageMongoRepository::class],
basePackages = ["me.coolrc.chatlog.repositories.mongo.chat_message"],
mongoTemplateRef = "primary-template"
)
class MongoConfigPrimary : AbstractMongoClientConfiguration() {

@Bean("primary-database")
@ConfigurationProperties(prefix="spring.database")
override fun getDatabaseName(): String {
return "chatlog"
}

@Primary
@Bean("primary-template")
override fun mongoTemplate(databaseFactory: MongoDatabaseFactory, converter: MappingMongoConverter): MongoTemplate {
return MongoTemplate(mongoClient(),databaseName)
}

@Bean("primary-client")
@ConfigurationProperties(prefix="spring.client")
override fun mongoClient(): MongoClient {
return MongoClients.create("mongodb://root:example@localhost:27017")
}
}


@Configuration("second")
@EnableMongoRepositories(basePackageClasses = [UserMongoRepository::class],
basePackages = ["me.coolrc.chatlog.repositories.mongo.user"],
mongoTemplateRef = "second-template"
)
//@EnableMongoRepositories(includeFilters = [ComponentScan.Filter(type = FilterType.REGEX, pattern = [".*UserMongoRepository"])])
class MongoConfigSecond : AbstractMongoClientConfiguration() {
@Bean("second-database")
override fun getDatabaseName(): String {
return "not_exist"
}

@Bean("second-template")
override fun mongoTemplate(databaseFactory: MongoDatabaseFactory, converter: MappingMongoConverter): MongoTemplate {
return MongoTemplate(mongoClient(),databaseName)
}


@Bean("second-client")
override fun mongoClient(): MongoClient {
return MongoClients.create("mongodb://root:example@localhost:27017")
}
}

还是用注解指定我们要scan的包或者类,注入对应repo,但是光这样还不够。

我们还要手动绑定TemplateRef,然后需要自己实现mongoTemplate。这是因为虽然我们只指定scan后,两个config注入对应的repo了,但是databaseFactory这个bean其实只有一个,生成的mongoTemplate也就只有一个。

所以我们要忽略掉databaseFactory,自己实现mongoTemplate(),手动new一个mongoTemplate。当然,你也可以实现mongoDbFactory()都是一样的效果。