huangzejun

本文分析的是 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 接口(以下省略了部分代码):

 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 }

核心构造方法:

/**
     * @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。

 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 一样。

 

分类:

技术点:

相关文章: