Spring-MongoDB 关键类的源码分析
本文分析的是 spring-data-mongodb-1.9.2.RELEASE.jar 和 mongodb-driver-core-3.2.2.jar。
一、UML Class Diagram
核心类是 MongoTemplate,下面这张 UML 类图涉及了主要的类,省略了次要的类。
涉及的类: MongoTemplate,
MongoOperations,
MongoDbFactory,
SimpleMongoDbFactory,
Mongo,
MongoClient,
MongoCredential,
ServerAddress。
二、源码分析
(1) MongoTemplate
MongoTemplate 是 Spring-MongoDB 整合的核心类,它实现了 MongoOperations 接口(该接口定义了 CRUD 操作)。
MongoTemplate 有个核心的构造方法(其他重载的构造方法最终都会调用这个构造方法):
- /**
- * Constructor used for a basic template configuration.
- *
- * @param mongoDbFactory must not be {@literal null}.
- * @param mongoConverter
- */
- public MongoTemplate(MongoDbFactory mongoDbFactory, MongoConverter mongoConverter) {
- Assert.notNull(mongoDbFactory);
- this.mongoDbFactory = mongoDbFactory;
- this.exceptionTranslator = mongoDbFactory.getExceptionTranslator();
- this.mongoConverter = mongoConverter == null ? getDefaultMongoConverter(mongoDbFactory) : mongoConverter;
- this.queryMapper = new QueryMapper(this.mongoConverter);
- this.updateMapper = new UpdateMapper(this.mongoConverter);
- // We always have a mapping context in the converter, whether it's a simple one or not
- mappingContext = this.mongoConverter.getMappingContext();
- // We create indexes based on mapping events
- if (null != mappingContext && mappingContext instanceof MongoMappingContext) {
- indexCreator = new MongoPersistentEntityIndexCreator((MongoMappingContext) mappingContext, mongoDbFactory);
- eventPublisher = new MongoMappingEventPublisher(indexCreator);
- if (mappingContext instanceof ApplicationEventPublisherAware) {
- ((ApplicationEventPublisherAware) mappingContext).setApplicationEventPublisher(eventPublisher);
- }
- }
- }
可以看到,这个构造方法至少需要一个参数 mongoDbFactory,MongoTemplate 类中其他字段都可以内部构造出来。
(2)MongoDbFactory
MongoDbFactory 是一个接口,用于新建 DB 实例。
它的实现之一是 SimpleMongoDbFactory。
- public interface MongoDbFactory {
- /**
- * Creates a default {@link DB} instance.
- *
- * @return
- * @throws DataAccessException
- */
- DB getDb() throws DataAccessException;
- /**
- * Creates a {@link DB} instance to access the database with the given name.
- *
- * @param dbName must not be {@literal null} or empty.
- * @return
- * @throws DataAccessException
- */
- DB getDb(String dbName) throws DataAccessException;
- /**
- * Exposes a shared {@link MongoExceptionTranslator}.
- *
- * @return will never be {@literal null}.
- */
- PersistenceExceptionTranslator getExceptionTranslator();
- }
(3) SimpleMongoDbFactory
SimpleMongoDbFactory 实现了 MongoDbFactory 接口(以下省略了部分代码):
- public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
- private final Mongo mongo;
- private final String databaseName;
- private final boolean mongoInstanceCreated;
- private final UserCredentials credentials;
- private final PersistenceExceptionTranslator exceptionTranslator;
- private final String authenticationDatabaseName;
- private WriteConcern writeConcern;
- /**
- * Creates a new {@link SimpleMongoDbFactory} instance from the given {@link MongoClientURI}.
- *
- * @param uri must not be {@literal null}.
- * @throws UnknownHostException
- * @since 1.7
- */
- public SimpleMongoDbFactory(MongoClientURI uri) throws UnknownHostException {
- this(new MongoClient(uri), uri.getDatabase(), true);
- }
- /**
- * Creates a new {@link SimpleMongoDbFactory} instance from the given {@link MongoClient}.
- *
- * @param mongoClient must not be {@literal null}.
- * @param databaseName must not be {@literal null}.
- * @since 1.7
- */
- public SimpleMongoDbFactory(MongoClient mongoClient, String databaseName) {
- this(mongoClient, databaseName, false);
- }
- private SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials,
- boolean mongoInstanceCreated, String authenticationDatabaseName) {
- if (mongo instanceof MongoClient && (credentials != null && !UserCredentials.NO_CREDENTIALS.equals(credentials))) {
- throw new InvalidDataAccessApiUsageException(
- "Usage of 'UserCredentials' with 'MongoClient' is no longer supported. Please use 'MongoCredential' for 'MongoClient' or just 'Mongo'.");
- }
- Assert.notNull(mongo, "Mongo must not be null");
- Assert.hasText(databaseName, "Database name must not be empty");
- Assert.isTrue(databaseName.matches("[\\w-]+"),
- "Database name must only contain letters, numbers, underscores and dashes!");
- this.mongo = mongo;
- this.databaseName = databaseName;
- this.mongoInstanceCreated = mongoInstanceCreated;
- this.credentials = credentials == null ? UserCredentials.NO_CREDENTIALS : credentials;
- this.exceptionTranslator = new MongoExceptionTranslator();
- this.authenticationDatabaseName = StringUtils.hasText(authenticationDatabaseName) ? authenticationDatabaseName
- : databaseName;
- Assert.isTrue(this.authenticationDatabaseName.matches("[\\w-]+"),
- "Authentication database name must only contain letters, numbers, underscores and dashes!");
- }
- /**
- * @param client
- * @param databaseName
- * @param mongoInstanceCreated
- * @since 1.7
- */
- private SimpleMongoDbFactory(MongoClient client, String databaseName, boolean mongoInstanceCreated) {
- Assert.notNull(client, "MongoClient must not be null!");
- Assert.hasText(databaseName, "Database name must not be empty!");
- this.mongo = client;
- this.databaseName = databaseName;
- this.mongoInstanceCreated = mongoInstanceCreated;
- this.exceptionTranslator = new MongoExceptionTranslator();
- this.credentials = UserCredentials.NO_CREDENTIALS;
- this.authenticationDatabaseName = databaseName;
- }
- }
核心构造方法:
- /**
- * @param client
- * @param databaseName
- * @param mongoInstanceCreated
- * @since 1.7
- */
- private SimpleMongoDbFactory(MongoClient client, String databaseName, boolean mongoInstanceCreated) {
- Assert.notNull(client, "MongoClient must not be null!");
- Assert.hasText(databaseName, "Database name must not be empty!");
- this.mongo = client;
- this.databaseName = databaseName;
- this.mongoInstanceCreated = mongoInstanceCreated;
- this.exceptionTranslator = new MongoExceptionTranslator();
- this.credentials = UserCredentials.NO_CREDENTIALS;
- this.authenticationDatabaseName = databaseName;
- }
第一个参数 MongoClient client(MongoClient): 包含 host, port, username, password 等信息。
(4)MongoClient 与 Mongo
MongoClient 继承了 Mongo。
- /**
- * Creates a Mongo instance based on a (single) mongo node using a given ServerAddress and default options.
- *
- * @param addr the database address
- * @param credentialsList the list of credentials used to authenticate all connections
- * @param options default options
- * @see com.mongodb.ServerAddress
- * @since 2.11.0
- */
- public MongoClient(final ServerAddress addr, final List<MongoCredential> credentialsList, final MongoClientOptions options) {
- super(addr, credentialsList, options);
- }
这个核心构造方法接收三个参数:
final ServerAddress addr:可以由 new ServerAddress(host, port) 构造。
final List<MongoCredential> credentialsList: 包含 username, password 等信息。
final MongoClientOptions options: 包含 MongoDB 数据库的配置信息。
(5) MongoCredential
MongoCredential 包含 username, password 等信息。
- public final class MongoCredential {
- private final AuthenticationMechanism mechanism;
- private final String userName;
- private final String source;
- private final char[] password;
- private final Map<String, Object> mechanismProperties;
- // Other code
- }
三、其他
Spring-MongoDB 整合与 Spring-MyBatis 相似。
Spring-MyBatis 的核心类是 SqlSessionTemplate,作用与 MongoTemplate 一样。
Spring-MongoDB 关键类的源码分析的更多相关文章
- Spring Boot 揭秘与实战 源码分析 - 工作原理剖析
文章目录 1. EnableAutoConfiguration 帮助我们做了什么 2. 配置参数类 – FreeMarkerProperties 3. 自动配置类 – FreeMarkerAutoCo ...
- Spring Boot 揭秘与实战 源码分析 - 开箱即用,内藏玄机
文章目录 1. 开箱即用,内藏玄机 2. 总结 3. 源代码 Spring Boot提供了很多”开箱即用“的依赖模块,那么,Spring Boot 如何巧妙的做到开箱即用,自动配置的呢? 开箱即用,内 ...
- Spring Environment(二)源码分析
Spring Environment(二)源码分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring Envi ...
- JDK中String类的源码分析(二)
1.startsWith(String prefix, int toffset)方法 包括startsWith(*),endsWith(*)方法,都是调用上述一个方法 public boolean s ...
- Spring Security(四) —— 核心过滤器源码分析
摘要: 原创出处 https://www.cnkirito.moe/spring-security-4/ 「老徐」欢迎转载,保留摘要,谢谢! 4 过滤器详解 前面的部分,我们关注了Spring Sec ...
- Set集合架构和常用实现类的源码分析以及实例应用
说明:Set的实现类都是基于Map来实现的(HashSet是通过HashMap实现的,TreeSet是通过TreeMap实现的). (01) Set 是继承于Collection的接口.它是一个不允许 ...
- Spring Cloud Eureka服务注册源码分析
Eureka是怎么work的 那eureka client如何将本地服务的注册信息发送到远端的注册服务器eureka server上.通过下面的源码分析,看出Eureka Client的定时任务调用E ...
- String类的源码分析
之前面试的时候被问到有没有看过String类的源码,楼主当时就慌了,回来赶紧补一课. 1.构造器(构造方法) String类提供了很多不同的构造器,分别对应了不同的字符串初始化方法,此处从源码中摘录如 ...
- Mybatis整合Spring实现事务管理的源码分析
一:前言 没有完整看完,但是看到了一些关键的地方,这里做个记录,过程会有点乱,以后逐渐补充最终归档为完整流程:相信看过框架源码的都知道过程中无法完全确定是怎样的流程,毕竟不可能全部都去测试一遍 ,但是 ...
随机推荐
- ubuntu14.04 编译安装highpoint rocketraid 2720驱动
highpoint官方只有ubuntu12.10驱动,对于ubuntu14.04或者12.04,需要手工编译安装驱动. 基本步骤: 1.下载rocketraid 2720驱动源代码 2.在一台装有ub ...
- freemarker之数组(十八)
1.设计思路 (1)声明一个数组 (2)打印数组中的元素 2.设计源码 <#--freemarker数组--> <#assign nums=[12,34,56,78,90,54,23 ...
- Hibernate最全面试题
Hibernate常见面试题 Hibernate工作原理及为什么要用? Hibernate工作原理及为什么要用? 读取并解析配置文件 读取并解析映射信息,创建SessionFactory 打开Sess ...
- swing 之简单登录窗体实现
swing之简单登陆窗体的实现 import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionLi ...
- es6中一些基本的使用方法
es6中一些基本的使用方法 const 定义常量 let 块级变量 用let定义的变量只在块当中起作用,离开变量外界的块(括号)就会被销毁. 模板字面量 用于字符串拼接和写模板,使用 ` (反引号,左 ...
- Luogu P3412 仓鼠找$sugar$ $II$
Luogu P3412 仓鼠找\(sugar\) \(II\) 题目大意: 给定一棵\(n\)个点的树, 仓鼠每次移动都会等概率选择一个与当前点相邻的点,并移动到此点. 现在随机生成一个起点.一个终点 ...
- [HNOI2011]XOR和路径 && [HNOI2013]游走
[HNOI2011]XOR和路径 题目大意 具体题目:戳我 题目: 给定一个n个点,m条边的有重边.有自环的无向图,其中每个边都有一个边权. 现在随机选择一条1到n的路径,路径权值为这条路径上所有边权 ...
- [BZOJ4736]温暖会指引我们前行
BZOJ(BZOJ上的是什么鬼...) UOJ 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低. 小 ...
- Poj3678:Katu Puzzle
大概题意 有\(n\)个数,可以为\(0/1\),给\(m\)个条件,表示某两个数经过\(or, and, xor\)后的数是多少 判断是否有解 Sol \(2-SAT\)判定 建图 # includ ...
- Luogu1121:环状最大两段子段和
题面 传送门 Sol 两种情况 第一种就是类似\(***000***000***(0表示选)\),这个可以DP 设\(h[0/1/2/3][i]\)表示到第\(i\)位的状态: \(0\):表示还没选 ...