文章目录
- 一、需求背景
- 二、实现步骤
- 1. 添加依赖
- 2. 修改配置文件
- 3. 重建数据源配置类
- AbstractMongoConfigure
- PrimaryMongoConfigure
- SecondaryMongoConfigure
- 4. 创建实体类与接口
- User
- UserRepository
- 5. 调用示例
一、需求背景
MongoDB 是一个基于分布式存储的数据库,具备开源、高性能等特点,是当前 NoSQL 数据库中比较热门的一种。
同 MySQL 一样,SpringBoot 对 MongoDB 单数据源已经实现了很好的集成,大部分情况下都可以满足用户的需求。
但本次我们的需求是在 SpringBoot 项目中实现 MongoDB 多数据源配置,这就需要我们在原生 API 的基础上做一些改造,详情请见下文分解。
二、实现步骤
1. 添加依赖
第一步,需要在 pom.xml
文件中添加如下依赖:
<!-- MongoDB -->
<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;
/**
* Mongo 配置抽象类
*
* @author xiepd
* @date 2019/7/16
*/
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();
// getter & setter
}
然后,创建分别对应 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;
/**
* @author xiepd
* @date 2019/7/16
*/
@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;
/**
* @author xiepd
* @date 2019/7/16
*/
@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;
// getter & setter
}
UserRepository
package com.panda.mongo.repository.primary;
import com.panda.mongo.entity.User;
import org.springframework.data.mongodb.repository.MongoRepository;
/**
* Created by xiepd on 2019/07/16.
*/
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;
/**
* Created by xiepd on 2019/07/16.
*/
@Service
public class UserService {
@Autowired
private UserRepository repository;
@Resource(name = "primaryMongoTemplate")
private MongoTemplate mongoTemplate;
// CRUD method
}
通常,repository
接口已经为我们预设好简单的增删改查方法,只需将 UserRepository
放置到正确的目录下,然后由 SpringBoot 注入即可。
若有复杂的业务,可直接获取 mongoTemplate
实例,然后实现其 CRUD 方法。该实例获取方式简单,通过 @Resource
注解并指明名称即可,SpringBoot 会自动从管理的 bean 中查找名称一致的 mongoTemplate
实例。