文章目录
一、需求背景二、实现步骤1. 添加依赖2. 修改配置文件3. 重建数据源配置类AbstractMongoConfigurePrimaryMongoConfigureSecondaryMongoConfigure
4. 创建实体类与接口UserUserRepository
5. 调用示例
一、需求背景
MongoDB 是一个基于分布式存储的数据库,具备开源、高性能等特点,是当前 NoSQL 数据库中比较热门的一种。
同 MySQL 一样,SpringBoot 对 MongoDB 单数据源已经实现了很好的集成,大部分情况下都可以满足用户的需求。
但本次我们的需求是在 SpringBoot 项目中实现 MongoDB 多数据源配置,这就需要我们在原生 API 的基础上做一些改造,详情请见下文分解。
二、实现步骤
1. 添加依赖
第一步,需要在 pom.xml 文件中添加如下依赖:
<dependency>
<groupId>org.springframework.boot
</groupId>
<artifactId>spring-boot-starter-data-mongodb
</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot
</groupId>
<artifactId>spring-boot-configuration-processor
</artifactId>
<optional>true
</optional>
</dependency>
2. 修改配置文件
第二步,在配置文件 application.properties 中添加多数据源的信息:
spring.data.mongodb.database=admin
spring.data.mongodb.host=127.0.0.1
spring.data.mongodb.port=27017
spring.data.mongodb.authenticationDatabase=admin
spring.data.mongodb.username=mongodb
spring.data.mongodb.password=mongodb
spring.data.mongodb.primary.database=primary_data
spring.data.mongodb.primary.host=127.0.0.1
spring.data.mongodb.primary.port=27017
spring.data.mongodb.primary.authenticationDatabase=admin
spring.data.mongodb.primary.username=mongodb
spring.data.mongodb.primary.password=mongodb
spring.data.mongodb.secondary.database=secondary_data
spring.data.mongodb.secondary.host=127.0.0.1
spring.data.mongodb.secondary.port=27017
spring.data.mongodb.secondary.authenticationDatabase=admin
spring.data.mongodb.secondary.username=mongodb
spring.data.mongodb.secondary.password=mongodb
需要注意的是,除了新增的 primary 与 secondary 数据源,原生的数据源也需进行正确配置。因为 SpringBoot 启动时会默认连接原生数据源,若没有正确配置,程序会抛出连接异常。当然,这个异常不会对程序其他部分造成影响。
3. 重建数据源配置类
第三步,需要重建数据源配置类,以替代默认的配置类 MongoProperties。
首先,创建数据源配置基类 AbstractMongoConfigure。
AbstractMongoConfigure
import com
.mongodb
.MongoClient
;
import com
.mongodb
.MongoClientOptions
;
import com
.mongodb
.MongoCredential
;
import com
.mongodb
.ServerAddress
;
import org
.springframework
.data
.mongodb
.MongoDbFactory
;
import org
.springframework
.data
.mongodb
.core
.MongoTemplate
;
import org
.springframework
.data
.mongodb
.core
.SimpleMongoDbFactory
;
public abstract class AbstractMongoConfigure {
private String database
;
private String host
;
private int port
;
private String authenticationDatabase
;
private String username
;
private char[] password
;
public MongoDbFactory
mongoDbFactory() {
MongoDbFactory factory
;
if (authenticationDatabase
!= null
&& username
!= null
&& password
!= null
) {
ServerAddress serverAddress
= new ServerAddress(host
, port
);
MongoCredential credential
= MongoCredential
.createCredential(username
, authenticationDatabase
, password
);
MongoClientOptions options
= MongoClientOptions
.builder().build();
factory
= new SimpleMongoDbFactory(new MongoClient(serverAddress
, credential
, options
), database
);
} else {
factory
= new SimpleMongoDbFactory(new MongoClient(host
, port
), database
);
}
return factory
;
}
public abstract MongoTemplate
getMongoTemplate();
}
然后,创建分别对应 primary 和 secondary 的配置类 PrimaryMongoConfigure 及 SecondaryMongoConfigure
PrimaryMongoConfigure
import org
.springframework
.boot
.context
.properties
.ConfigurationProperties
;
import org
.springframework
.context
.annotation
.Bean
;
import org
.springframework
.context
.annotation
.Primary
;
import org
.springframework
.data
.mongodb
.core
.MongoTemplate
;
import org
.springframework
.data
.mongodb
.repository
.config
.EnableMongoRepositories
;
import org
.springframework
.stereotype
.Component
;
@Component
@ConfigurationProperties(prefix
= "spring.data.mongodb.primary")
@EnableMongoRepositories(basePackages
= "com.panda.mongo.repository.primary", mongoTemplateRef
= "primaryMongoTemplate")
public class PrimaryMongoConfigure extends AbstractMongoConfigure {
@Override
@Primary
@Bean(name
= "primaryMongoTemplate")
public MongoTemplate
getMongoTemplate() {
return new MongoTemplate(mongoDbFactory());
}
}
SecondaryMongoConfigure
import org
.springframework
.boot
.context
.properties
.ConfigurationProperties
;
import org
.springframework
.context
.annotation
.Bean
;
import org
.springframework
.data
.mongodb
.core
.MongoTemplate
;
import org
.springframework
.data
.mongodb
.repository
.config
.EnableMongoRepositories
;
import org
.springframework
.stereotype
.Component
;
@Component
@ConfigurationProperties(prefix
= "spring.data.mongodb.secondary")
@EnableMongoRepositories(basePackages
= "com.panda.mongo.repository.secondary", mongoTemplateRef
= "secondaryMongoTemplate")
public class SecondaryMongoConfigure extends AbstractMongoConfigure {
@Override
@Bean(name
= "secondaryMongoTemplate")
public MongoTemplate
getMongoTemplate() {
return new MongoTemplate(mongoDbFactory());
}
}
在以上代码中,出现了多种注解,现对关键项作简要说明:
@ConfigurationProperties:声明该类为配置类,可读取配置文件中相同配置项的值。例如,设前缀 prefix 为 user,则当前类的 name 属性可取配置文件中 user.name 的值@EnableMongoRepositories:配置 repository 目录与 mongoTemplate 的对应关系,即指明某个目录下的 repository 接口采用哪个 mongoTemplate。此 mongoTemplate 与数据源一一对应@Primary:声明该数据源为主要数据源,若没有添加该注解,SpringBoot 在生成 bean 的时候会抛出异常
4. 创建实体类与接口
第四步,创建数据实体 User 与操作接口 UserRepository:
User
import org
.springframework
.data
.annotation
.Id
;
import org
.springframework
.data
.mongodb
.core
.mapping
.Document
;
import org
.springframework
.data
.mongodb
.core
.mapping
.Field
;
@Document(collection
= "user")
public class User {
@Id
private String id
;
@Field(value
= "name")
private String name
;
@Field(value
= "age")
private Integer age
;
}
UserRepository
package com
.panda
.mongo
.repository
.primary
;
import com
.panda
.mongo
.entity
.User
;
import org
.springframework
.data
.mongodb
.repository
.MongoRepository
;
public interface UserRepository extends MongoRepository<User, String> {
}
需要特别注意的是,repository 所在的目录就决定了它所对应的 mongoTemplate,不可放错目录。
5. 调用示例
最后一步,我们创建 Service 实现调用:
import com
.panda
.mongo
.repository
.primary
.UserRepository
;
import org
.springframework
.beans
.factory
.annotation
.Autowired
;
import org
.springframework
.data
.mongodb
.core
.MongoTemplate
;
import org
.springframework
.stereotype
.Service
;
import javax
.annotation
.Resource
;
@Service
public class UserService {
@Autowired
private UserRepository repository
;
@Resource(name
= "primaryMongoTemplate")
private MongoTemplate mongoTemplate
;
}
通常,repository 接口已经为我们预设好简单的增删改查方法,只需将 UserRepository 放置到正确的目录下,然后由 SpringBoot 注入即可。
若有复杂的业务,可直接获取 mongoTemplate 实例,然后实现其 CRUD 方法。该实例获取方式简单,通过 @Resource 注解并指明名称即可,SpringBoot 会自动从管理的 bean 中查找名称一致的 mongoTemplate 实例。