本文分析的是 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 有个核心的构造方法(其他重载的构造方法最终都会调用这个构造方法):

  1. /**
  2. * Constructor used for a basic template configuration.
  3. *
  4. * @param mongoDbFactory must not be {@literal null}.
  5. * @param mongoConverter
  6. */
  7. public MongoTemplate(MongoDbFactory mongoDbFactory, MongoConverter mongoConverter) {
  8.  
  9. Assert.notNull(mongoDbFactory);
  10.  
  11. this.mongoDbFactory = mongoDbFactory;
  12. this.exceptionTranslator = mongoDbFactory.getExceptionTranslator();
  13. this.mongoConverter = mongoConverter == null ? getDefaultMongoConverter(mongoDbFactory) : mongoConverter;
  14. this.queryMapper = new QueryMapper(this.mongoConverter);
  15. this.updateMapper = new UpdateMapper(this.mongoConverter);
  16.  
  17. // We always have a mapping context in the converter, whether it's a simple one or not
  18. mappingContext = this.mongoConverter.getMappingContext();
  19. // We create indexes based on mapping events
  20. if (null != mappingContext && mappingContext instanceof MongoMappingContext) {
  21. indexCreator = new MongoPersistentEntityIndexCreator((MongoMappingContext) mappingContext, mongoDbFactory);
  22. eventPublisher = new MongoMappingEventPublisher(indexCreator);
  23. if (mappingContext instanceof ApplicationEventPublisherAware) {
  24. ((ApplicationEventPublisherAware) mappingContext).setApplicationEventPublisher(eventPublisher);
  25. }
  26. }
  27. }

可以看到,这个构造方法至少需要一个参数 mongoDbFactory,MongoTemplate 类中其他字段都可以内部构造出来。

(2)MongoDbFactory

MongoDbFactory 是一个接口,用于新建 DB 实例。

它的实现之一是 SimpleMongoDbFactory。

  1. public interface MongoDbFactory {
  2.  
  3. /**
  4. * Creates a default {@link DB} instance.
  5. *
  6. * @return
  7. * @throws DataAccessException
  8. */
  9. DB getDb() throws DataAccessException;
  10.  
  11. /**
  12. * Creates a {@link DB} instance to access the database with the given name.
  13. *
  14. * @param dbName must not be {@literal null} or empty.
  15. * @return
  16. * @throws DataAccessException
  17. */
  18. DB getDb(String dbName) throws DataAccessException;
  19.  
  20. /**
  21. * Exposes a shared {@link MongoExceptionTranslator}.
  22. *
  23. * @return will never be {@literal null}.
  24. */
  25. PersistenceExceptionTranslator getExceptionTranslator();
  26. }

(3) SimpleMongoDbFactory

SimpleMongoDbFactory 实现了 MongoDbFactory 接口(以下省略了部分代码):

  1. public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
  2.  
  3. private final Mongo mongo;
  4. private final String databaseName;
  5. private final boolean mongoInstanceCreated;
  6. private final UserCredentials credentials;
  7. private final PersistenceExceptionTranslator exceptionTranslator;
  8. private final String authenticationDatabaseName;
  9.  
  10. private WriteConcern writeConcern;
  11.  
  12. /**
  13. * Creates a new {@link SimpleMongoDbFactory} instance from the given {@link MongoClientURI}.
  14. *
  15. * @param uri must not be {@literal null}.
  16. * @throws UnknownHostException
  17. * @since 1.7
  18. */
  19. public SimpleMongoDbFactory(MongoClientURI uri) throws UnknownHostException {
  20. this(new MongoClient(uri), uri.getDatabase(), true);
  21. }
  22.  
  23. /**
  24. * Creates a new {@link SimpleMongoDbFactory} instance from the given {@link MongoClient}.
  25. *
  26. * @param mongoClient must not be {@literal null}.
  27. * @param databaseName must not be {@literal null}.
  28. * @since 1.7
  29. */
  30. public SimpleMongoDbFactory(MongoClient mongoClient, String databaseName) {
  31. this(mongoClient, databaseName, false);
  32. }
  33.  
  34. private SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials,
  35. boolean mongoInstanceCreated, String authenticationDatabaseName) {
  36.  
  37. if (mongo instanceof MongoClient && (credentials != null && !UserCredentials.NO_CREDENTIALS.equals(credentials))) {
  38. throw new InvalidDataAccessApiUsageException(
  39. "Usage of 'UserCredentials' with 'MongoClient' is no longer supported. Please use 'MongoCredential' for 'MongoClient' or just 'Mongo'.");
  40. }
  41.  
  42. Assert.notNull(mongo, "Mongo must not be null");
  43. Assert.hasText(databaseName, "Database name must not be empty");
  44. Assert.isTrue(databaseName.matches("[\\w-]+"),
  45. "Database name must only contain letters, numbers, underscores and dashes!");
  46.  
  47. this.mongo = mongo;
  48. this.databaseName = databaseName;
  49. this.mongoInstanceCreated = mongoInstanceCreated;
  50. this.credentials = credentials == null ? UserCredentials.NO_CREDENTIALS : credentials;
  51. this.exceptionTranslator = new MongoExceptionTranslator();
  52. this.authenticationDatabaseName = StringUtils.hasText(authenticationDatabaseName) ? authenticationDatabaseName
  53. : databaseName;
  54.  
  55. Assert.isTrue(this.authenticationDatabaseName.matches("[\\w-]+"),
  56. "Authentication database name must only contain letters, numbers, underscores and dashes!");
  57. }
  58.  
  59. /**
  60. * @param client
  61. * @param databaseName
  62. * @param mongoInstanceCreated
  63. * @since 1.7
  64. */
  65. private SimpleMongoDbFactory(MongoClient client, String databaseName, boolean mongoInstanceCreated) {
  66.  
  67. Assert.notNull(client, "MongoClient must not be null!");
  68. Assert.hasText(databaseName, "Database name must not be empty!");
  69.  
  70. this.mongo = client;
  71. this.databaseName = databaseName;
  72. this.mongoInstanceCreated = mongoInstanceCreated;
  73. this.exceptionTranslator = new MongoExceptionTranslator();
  74. this.credentials = UserCredentials.NO_CREDENTIALS;
  75. this.authenticationDatabaseName = databaseName;
  76. }
  77.  
  78. }

核心构造方法:

  1. /**
  2. * @param client
  3. * @param databaseName
  4. * @param mongoInstanceCreated
  5. * @since 1.7
  6. */
  7. private SimpleMongoDbFactory(MongoClient client, String databaseName, boolean mongoInstanceCreated) {
  8.  
  9. Assert.notNull(client, "MongoClient must not be null!");
  10. Assert.hasText(databaseName, "Database name must not be empty!");
  11.  
  12. this.mongo = client;
  13. this.databaseName = databaseName;
  14. this.mongoInstanceCreated = mongoInstanceCreated;
  15. this.exceptionTranslator = new MongoExceptionTranslator();
  16. this.credentials = UserCredentials.NO_CREDENTIALS;
  17. this.authenticationDatabaseName = databaseName;
  18. }

第一个参数 MongoClient client(MongoClient): 包含 host, port, username, password 等信息。

(4)MongoClient 与 Mongo

MongoClient 继承了 Mongo。

  1. /**
  2. * Creates a Mongo instance based on a (single) mongo node using a given ServerAddress and default options.
  3. *
  4. * @param addr the database address
  5. * @param credentialsList the list of credentials used to authenticate all connections
  6. * @param options default options
  7. * @see com.mongodb.ServerAddress
  8. * @since 2.11.0
  9. */
  10. public MongoClient(final ServerAddress addr, final List<MongoCredential> credentialsList, final MongoClientOptions options) {
  11. super(addr, credentialsList, options);
  12. }

这个核心构造方法接收三个参数:

final ServerAddress addr:可以由 new ServerAddress(host, port) 构造。

final List<MongoCredential> credentialsList: 包含 username, password 等信息。

final MongoClientOptions options: 包含 MongoDB 数据库的配置信息。

(5) MongoCredential

MongoCredential 包含 username, password 等信息。

  1. public final class MongoCredential {
  2.  
  3. private final AuthenticationMechanism mechanism;
  4. private final String userName;
  5. private final String source;
  6. private final char[] password;
  7. private final Map<String, Object> mechanismProperties;
  8.  
  9. // Other code
  10. }

三、其他

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. ubuntu14.04 编译安装highpoint rocketraid 2720驱动

    highpoint官方只有ubuntu12.10驱动,对于ubuntu14.04或者12.04,需要手工编译安装驱动. 基本步骤: 1.下载rocketraid 2720驱动源代码 2.在一台装有ub ...

  2. freemarker之数组(十八)

    1.设计思路 (1)声明一个数组 (2)打印数组中的元素 2.设计源码 <#--freemarker数组--> <#assign nums=[12,34,56,78,90,54,23 ...

  3. Hibernate最全面试题

    Hibernate常见面试题 Hibernate工作原理及为什么要用? Hibernate工作原理及为什么要用? 读取并解析配置文件 读取并解析映射信息,创建SessionFactory 打开Sess ...

  4. swing 之简单登录窗体实现

    swing之简单登陆窗体的实现 import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionLi ...

  5. es6中一些基本的使用方法

    es6中一些基本的使用方法 const 定义常量 let 块级变量 用let定义的变量只在块当中起作用,离开变量外界的块(括号)就会被销毁. 模板字面量 用于字符串拼接和写模板,使用 ` (反引号,左 ...

  6. Luogu P3412 仓鼠找$sugar$ $II$

    Luogu P3412 仓鼠找\(sugar\) \(II\) 题目大意: 给定一棵\(n\)个点的树, 仓鼠每次移动都会等概率选择一个与当前点相邻的点,并移动到此点. 现在随机生成一个起点.一个终点 ...

  7. [HNOI2011]XOR和路径 && [HNOI2013]游走

    [HNOI2011]XOR和路径 题目大意 具体题目:戳我 题目: 给定一个n个点,m条边的有重边.有自环的无向图,其中每个边都有一个边权. 现在随机选择一条1到n的路径,路径权值为这条路径上所有边权 ...

  8. [BZOJ4736]温暖会指引我们前行

    BZOJ(BZOJ上的是什么鬼...) UOJ 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低. 小 ...

  9. Poj3678:Katu Puzzle

    大概题意 有\(n\)个数,可以为\(0/1\),给\(m\)个条件,表示某两个数经过\(or, and, xor\)后的数是多少 判断是否有解 Sol \(2-SAT\)判定 建图 # includ ...

  10. Luogu1121:环状最大两段子段和

    题面 传送门 Sol 两种情况 第一种就是类似\(***000***000***(0表示选)\),这个可以DP 设\(h[0/1/2/3][i]\)表示到第\(i\)位的状态: \(0\):表示还没选 ...