本文分析的是 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 关键类的源码分析的更多相关文章

  1. Spring Boot 揭秘与实战 源码分析 - 工作原理剖析

    文章目录 1. EnableAutoConfiguration 帮助我们做了什么 2. 配置参数类 – FreeMarkerProperties 3. 自动配置类 – FreeMarkerAutoCo ...

  2. Spring Boot 揭秘与实战 源码分析 - 开箱即用,内藏玄机

    文章目录 1. 开箱即用,内藏玄机 2. 总结 3. 源代码 Spring Boot提供了很多”开箱即用“的依赖模块,那么,Spring Boot 如何巧妙的做到开箱即用,自动配置的呢? 开箱即用,内 ...

  3. Spring Environment(二)源码分析

    Spring Environment(二)源码分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring Envi ...

  4. JDK中String类的源码分析(二)

    1.startsWith(String prefix, int toffset)方法 包括startsWith(*),endsWith(*)方法,都是调用上述一个方法 public boolean s ...

  5. Spring Security(四) —— 核心过滤器源码分析

    摘要: 原创出处 https://www.cnkirito.moe/spring-security-4/ 「老徐」欢迎转载,保留摘要,谢谢! 4 过滤器详解 前面的部分,我们关注了Spring Sec ...

  6. Set集合架构和常用实现类的源码分析以及实例应用

    说明:Set的实现类都是基于Map来实现的(HashSet是通过HashMap实现的,TreeSet是通过TreeMap实现的). (01) Set 是继承于Collection的接口.它是一个不允许 ...

  7. Spring Cloud Eureka服务注册源码分析

    Eureka是怎么work的 那eureka client如何将本地服务的注册信息发送到远端的注册服务器eureka server上.通过下面的源码分析,看出Eureka Client的定时任务调用E ...

  8. String类的源码分析

    之前面试的时候被问到有没有看过String类的源码,楼主当时就慌了,回来赶紧补一课. 1.构造器(构造方法) String类提供了很多不同的构造器,分别对应了不同的字符串初始化方法,此处从源码中摘录如 ...

  9. Mybatis整合Spring实现事务管理的源码分析

    一:前言 没有完整看完,但是看到了一些关键的地方,这里做个记录,过程会有点乱,以后逐渐补充最终归档为完整流程:相信看过框架源码的都知道过程中无法完全确定是怎样的流程,毕竟不可能全部都去测试一遍 ,但是 ...

随机推荐

  1. linux下ssd电子盘速度检测

    代码: #include<stdio.h> #include<sys/time.h> #include <fcntl.h> #include <pthread ...

  2. Flex内存泄露解决方法和内存释放优化原则

    Flex内存泄露解决方法和内存释放优化原则 你对Flex内存泄露的概念是否了解,这里和大家分享一下Flex内存释放优化原则和Flex内存泄露解决方法,希望本文的介绍能让你有所收获. Flex内存释放优 ...

  3. vxWorks下dosFs文件系统的创建

    .cdromFs:允许系统从按照ISO9660标准文件系统格式化的CD-ROM上读取设备: 通常文件系统驱动位于磁盘(块存取)设备驱动和IO系统之间,这一点在VxWorks中也不例外,但它在此基础上扩 ...

  4. 芝麻HTTP:批量部署Splash负载集群

    安装Ansible: 看官方文档去:http://www.ansible.com.cn/index.html 好像这个主控端不支持Windows? 大家虚拟机装个Ubuntu吧. 闲话少扯直接上干货: ...

  5. BUAA软工第0次作业

    第一部分:结缘计算机 1.你为什么选择计算机专业?你认为你的条件如何?和这些博主比呢?(必答) 我在大学之前甚至连一个萌新都算不上,根本没有任何一点计算机专业的基础. 因此在进入大学之前,计算机对于我 ...

  6. java 值传递和引用传递

    public class PassValue { /** * 值传递 基本数据类型参数 * 值传递:方法调用时,实际参数吧他的值传递给对应的形式参数,方法执行中形式参数值的改变不影响实际参数的值 */ ...

  7. WC2006水管局长(加强)

    倒过来就变成了加边 然后就直接LCT # include <stdio.h> # include <stdlib.h> # include <iostream> # ...

  8. linux下线程的两种封装方式

    在网络编程的时候往往需要对Linux下原生的pthread库中的函数进行封装,使其使用起来更加方便,封装方法一般有两种:面向对象和基于对象,下面将分别介绍这两种方式,最后统一分析这两种方式的优缺点: ...

  9. About Windows 10 SDK Preview Build 17110

    在 Windows Developer Day 活动同时,微软正式 Release 了 Windows 10 SDK Preview Build 17110. Windows 10 SDK Previ ...

  10. GeoJSON JS判断某一点是否在某一区域范围之内

    GeoJSON JS判断某一点是否在某一区域范围之内 算法: function isInPolygon(checkPoint, polygonPoints) { var counter = 0; va ...