MongoDB study notes (11) - adding documents

This blog post begins to explain the operation of MongoDB.

First, let’s talk about the add document operation of MongoDB. In this blog post, I will explain how to insert MongoDB documents from the aspects of shell, js script, MongoDB Compass, java native driver, and spring package.

MongoDB shell

From the collection methods summarized by the previous methods, we can see that the shell provides three insertion methods:

  • db.collection.insert() : Insert one or more specified documents

    Its syntax is:

db.collection.insert(
   <document or array of documents>,
   {
     writeConcern: <document>,
     ordered: <boolean>
   }
)
  • db.collection.insertOne() : inserts a specified document

Its syntax is:

db.collection.insertOne(
   <document>,
   {
      writeConcern: <document>
   }
)
  • db.collection.insertMany() : Insert multiple specified documents

Its syntax is:

db.collection.insertMany(
   [ <document 1> , <document 2>, ... ],
   {
      writeConcern: <document>,
      ordered: <boolean>
   }
)

The above method has three main parameters:

document – ​​This parameter refers to the data of one or more documents to be inserted. If it is one document, the parameter is a json data. If there are multiple documents, the parameter is an array of multiple json data.

writeConcern – optional parameter, this parameter refers to the write concern degree of this insert operation. Its value is a document, which is expressed as json data. You can refer to the previous explanation of writing attention.

ordered - new parameter since version 2.6, optional parameter. If the value is true, the documents in the array will be inserted in order, if an error occurs in one document, mongodb will return without processing the remaining documents in the array. If false, perform an out-of-order insertion, and if the error occurs in a document, continue processing the remaining documents in the array. Defaults to true.

Note:
1. The above three methods are collection methods, so we need to have a corresponding collection. Of course, if the specified collection does not exist when we execute the method, MongoDB will automatically create the collection and insert data.
2. If the document does not specify the "_id" field, then mongodb will assign a unique objectid to the document before inserting, and insert the objectId into the document as the "_id" field. If the document contains an "_id" field, the _id value must be unique in the collection to avoid duplicate key errors.

For example, as shown in the figure below, I use several insert methods to demonstrate inserting data. Since insertOne() and insertMany() are similar to this method, they will not be demonstrated:
write picture description here

The above figure shows several aspects such as inserting only one piece of data, inserting one piece of data + writing attention, inserting multiple pieces of data + writing attention + sorting.
The above mongoTest collection did not exist originally, we can call it directly db.mongoTest.insert(...)to create and insert data by default.

After we use the insert() method to insert a document in the shell, regardless of error or failure, a BulkWriteResult() object will be returned, which internally describes the result of the insertion operation.

As can be seen from the inserted data above, when inserting data in the same collection, we do not have to follow that each document must have the same field name, and even the same field name can have different types in different documents. MongoDB is more flexible than relational databases in this regard. Of course, it is recommended that you put the same type of documents in one collection, and different types of documents in different collections.

js script
In addition to inserting data in the shell, we can also insert data in a js script file. We can first create a new script file, and then use the JavaScript syntax and the methods provided by the shell in the file to execute the js script to operate the database.

For example the following statement:

//获取数据库链接
var db = connect("localhost/words","yfl","yfl");
//自定义文档
var document1 = {key:"mongo_js",value:"测试js脚本插入数据"};
//调用集合mongoTest的insert方法
db.mongoTest.insert(document1);

var document2 = {key:"mongo_js2",value:"测试js脚本插入数据,附带参数"};
//自定义带有写入关注和是否顺序插入参数
var options = {writeConcern: { w: "majority", wtimeout: 5000 },ordered: false }
//带参数插入数据
db.mongoTest.insert(document2,options);

//自定义多个文档
var document3 = {key:"mongo_js3",value:"测试js脚本批量插入数据"};
var document4 = {key:"mongo_js4",value:"测试js脚本批量插入数据"};
//自定义一个文档数组,用于存放文档
var documentArray = new Array();
//调用数组的push方法将文档添加进数组
documentArray.push(document3);
documentArray.push(document4);
//将数组传入insert方法实现批量插入
db.mongoTest.insert(documentArray);
//获取集合对象
var mongoTest = db.getCollection("mongoTest");
//查询“key”这个键的值在"mongo_js","mongo_js4","mongo_js2","mongo_js3"之中的记录
var cursor = mongoTest.find({key:{$in:["mongo_js","mongo_js4","mongo_js2","mongo_js3"]}});
//打印出查询的数据
printjson(cursor.toArray());

The above code is the code of the data inserted in js. From the above code, we can see that we can use both JavaScript syntax and shell methods in the js file. Compared with operating the database in the shell, the js script to operate the database can be more flexible, and it is easy to modify, easy to save records, and can be executed regularly.

To execute the js script, you only need to switch to the bin directory of the mongoDB installation directory in cmd.exe, and execute it directly mongo js脚本路径, as shown below:
write picture description here

We can use MongoDB Compass to view the above insertion results, as shown below:
write picture description here

MongoDB Compass

In the above exercise, we used the shell to insert 5 pieces of data. At this time, we can use MongoDB Compass to view the previous data, as shown in the figure:
write picture description here
We can see that the data inserted by the above operation can be seen here.

Let's start by demonstrating how to insert data in MongoDB Compass:

First, we click the green "INSERT DOCUMENT" button on the upper left, as shown in the figure:
write picture description here

Then enter the data we want to insert, as shown in the figure:
write picture description here

Click "INSERT" or "CANCEL" to confirm or cancel the insert operation. After confirmation, we can see the data just inserted:
write picture description here

Inserting data in MongoDB Compass is very simple, and can only insert one item at a time.

MongoDB java Driver

The next step is to explain how to use MongoDB's java driver to operate MongoDB. For the specific preparation and introduction, you can refer to the study notes (10).

Look at the code below:

    /**
     * 用于演示MongoDB原生驱动添加数据
     */
    public void addDataDemo1(){
        // 获取MongoClient对象
        MongoClient client = null;
       // 直接使用默认host和port(该方法不能进行数据库授权认证)
//        client = new MongoClient();

       // 使用指定host和端口号,(该方法不能进行数据库授权认证)
//        client = new MongoClient("localhost",27017);

        // 使用封装的ServerAddress链接对象,无需授权时
//        client = new MongoClient(new ServerAddress("localhost",27017));
        // 使用封装的ServerAddress链接对象,需授权时,使用MongoCredential对象封装授权信息createCredential(String userName, String database, char[] password),
        // MongoDB 的java驱动的文档中的授权说是可以缺少 MongoClientOptions的,但是在其api文档中并没有提供只有 ServerAddress、MongoCredential的构造方法,估计是他们文档更新不及时,这里就直接加上 MongoClientOptions参数。
//        client = new MongoClient(new ServerAddress("localhost",27017), MongoCredential.createCredential("yfl","words","yfl".toCharArray()),MongoClientOptions.builder().build());

       // 使用URI链接MongoDB,MonoClientURI格式为:mongodb://[用户名:密码@]host:port[/数据库],强烈建议使用该种身份验证
        client = new MongoClient(new MongoClientURI("mongodb://yfl:yfl@localhost:27017/words"));

        //获取MongoDatabase 对象
        MongoDatabase database = client.getDatabase("words");
        //获取集合对象
        MongoCollection col = database.getCollection("mongoTest");

        //创建将要插入的文档对象,插入的文档类型必须是Document类型
        Document document = new Document("javakey","sss").append("value",5);
        col.insertOne(document);

        Document document1 = new Document("javakey","策划").append("value",5);
        Document document2 = new Document("javakey","sdsd").append("value",10);
        List list = new ArrayList();
        list.add(document1);
        list.add(document2);
        col.insertMany(list);
    }

First of all, I explained how we can obtain the MongoClient object in the java program. In the program, MongoDB may not have permission authentication turned on, or it may have permission authentication turned on. When permission authentication is not turned on, we can see that the method of obtaining the MongoClient object is fast Can.

However, after enabling authorization authentication, there are only two ways to obtain authorization and obtain the MongoClient object. In the previous version, you could first obtain the MongoClient object, then obtain the corresponding database, and call the authorization method of the database to authorize, but the new version seems to be This authentication method is canceled, and the authentication can only be authenticated when the MongoClient object is obtained.

There are two ways to obtain MongoClient identity authorization:

1. When using the constructor of MongoClient, pass in three parameters of ServerAddress+MongoCredential+MongoClientOptions. The ServerAddress parameter is to describe the host and port of the database to be linked. MongoCredential is the authentication information describing the database to be connected, including username, password, and database name to be linked. MongoClientOptions describes various settings to control the behavior of MongoClient.

2. Use the MongoClientURI object to describe the information and permission information of the database to be linked, and then pass in the MongoClientURI object when constructing the MongoClient object.

Of course, out of the construction methods demonstrated above, MongoClient also provides more construction methods. You can refer to the method list and official documentation of the MongoClient object in the previous article.

After obtaining the MongoClient object, we can obtain the corresponding MongoDatabase and MongoCollection objects, and after obtaining the collection object (MongoCollection), we can call the insert method provided by it, as shown in the figure:
write picture description here

It provides 8 insert methods, of which four are for inserting a single document, and four are for inserting multiple documents. The parameters passed in are different, and several parameters are designed:

Object tDocument – ​​This parameter is the database document data to be inserted. The type of the method provided in the official API document is TDocument, but MongoDB does not provide a TDocument object. In this example, TDocument only indicates that the parameter is a document type. Specifically, we should use the Document object when inserting, which corresponds to using BasicDBObject in the previous version, but the new version does not support this type as document data. When inserting data, if the type of document data is incorrect, it will be reported *** cannot be cast to org.bson.Document.

List – This parameter indicates List<Document>the list of documents to be inserted.

ClientSession – the client session associated with this operation

InsertOneOptions – Options applied to actions that insert a single document into the collection.

InsertManyOptions – Options that apply to operations that insert multiple documents into a collection.

Everyone above can view the corresponding official documents.

So in the above code I just insert a single document, a multi-document insert. The result is:
write picture description here

It can be seen from the above code that the code is relatively cumbersome, and the connection needs to be obtained every time, just like the operation of the previous relational database, and the inserted data must be a standard Document object, so that if there are nested documents in the document, the It is very troublesome, and sometimes, the data we store cannot determine its key value, and sometimes we want to store any type of data directly into it, which is very troublesome. So in order to solve this problem, spring encapsulates the driver. for spring-data-mongodb.

mongoTemplate

This object is an object exposed as spring-data-mongodb by the java driver that encapsulates MongoDB in spring. In practical applications, we only need to configure it accordingly. As for how to configure it, please see the previous blog post, which will not be introduced here. .

The application of mongoTemplate is very simple, you only need to inject the MongoTemplate object where it is used, for example:

    @Autowired
    private MongoTemplate mongoTemplate;

Since the link to the database is configured in the configuration file, we don't need to troublesomely obtain various objects here. We only need to directly operate the insert method of mongoTemplate:
write picture description here

As can be seen from the above figure, mongoTemplate provides us with 6 insert methods, 3 batch inserts and 3 single inserts.
There are only three main parameters:
Collection "? extends Object" / Object batchToSave : This parameter is the data we want to insert, and its type is a class that inherits Object, that is to say, as long as it is all data types that inherit from Object, we can By storing this method , the encapsulation class will help us convert the data type by itself.

collectionName : which collection we will store the data in. If this parameter is not present, mongoTemplate will automatically store it in the default collection.

Class entityClass : The class of the entity class that mongoTemplate uses to determine the collection that will store the database.

Note: As for mongoTemplate, when we do not pass collectionName or entityClass how to determine the stored collection,
( after actual testing, the default collection name stored is the type of the type to store data, such as com.alibaba.fastjson.JSONObject stored to In the jSONObject collection, the com.mongo.mongodb.Business.entity.MongoAddDemo entity class stores the mongoAddDemo" collection, that is, the first letter of the class class is lowercase as the collection name. However, the data of the HashMap type cannot be stored, and an error will be reported )

If you are interested in studying how mongoTemplate determines the default collection name, you can see the source code at the bottom (the analysis is very messy and complicated). The following is the method of adding data using mongoTemplate operation.

package com.mongo.mongodb.Business;

import com.alibaba.fastjson.JSONObject;
import com.mongo.mongodb.Business.entity.MongoAddDemo;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class MongodbTest {

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 使用spring封装mongodb的对象mongoTemplate添加数据
     */
    public void addDataDemo2(){

        //因为如果要是用mongoTemplate对象来操作MongoDB,我们首先需要配置要链接的数据库,所以我们就不在需要获取各种对象了,
        //只需要将mongoTemplate注入进来,然后操作insert方法
        JSONObject json = new JSONObject();
        json.put("key","json");
        json.put("value","测试存放json");
        mongoTemplate.insert(json,"mongoTest");//添加json数据

        Map map = new HashMap();
        map.put("key","map");
        map.put("value","测试存放map");
        mongoTemplate.insert(map,"mongoTest");//添加map数据

        MongoAddDemo entity = new MongoAddDemo();
        entity.setKey("entity");
        entity.setValue("测试存放entity");
        mongoTemplate.insert(entity,"mongoTest");//添加entity数据

    }
}

The result is as follows:
write picture description here

Note: If the data of the entity class type contains the "id" field, the mongoTemplate will automatically convert it to the "_id" field of mongo when it is stored.
————————————————————————————————————————————————–

Get the default collection name source code:

    //1.MongoTemplate类
    //首先根据根据传入的文档数据调用determineEntityCollectionName方法确定集合名称
    public void insert(Object objectToSave) {
        Assert.notNull(objectToSave, "ObjectToSave must not be null!");
        this.ensureNotIterable(objectToSave);
        this.insert(objectToSave, this.determineEntityCollectionName(objectToSave));
    }

    //2.MongoTemplate类
    //对传进的参数进行判空,若参数不为空,则使用传入的文档数据对象调用getClass()获取该对象的class并作为参数调用determineCollectionName方法,来确定集合名称
    private <T> String determineEntityCollectionName(@Nullable T obj) {
        return null != obj ? this.determineCollectionName(obj.getClass()) : null;
    }

    //3.MongoTemplate类
    //首先对传入的class判空,然后调用mappingContext类的getRequiredPersistentEntity()方法,并将返回值强转为MongoPersistentEntity对象,
    //然后获取到MongoPersistentEntity对象的getCollection()获取集合名称。从这里可以看出关键在于mappingContext.getRequiredPersistentEntity(entityClass)方法
    String determineCollectionName(@Nullable Class<?> entityClass) {
        if (entityClass == null) {
            throw new InvalidDataAccessApiUsageException("No class parameter provided, entity collection can't be determined!");
        } else {
        //如果大家对getRequiredPersistentEntity方法是如何将class对象转换成MongoPersistentEntity对象可以看下面的源码。
            return ((MongoPersistentEntity)this.mappingContext.getRequiredPersistentEntity(entityClass)).getCollection();
        }
    }

    //4.MongoPersistentEntity类
    //该类是一个接口类,其提供了四个接口方法,其中getCollection()方法用于提供获取集合名称的方法
    public interface MongoPersistentEntity<T> extends PersistentEntity<T, MongoPersistentProperty> {
        String getCollection();

        String getLanguage();

        @Nullable
        MongoPersistentProperty getTextScoreProperty();

        boolean hasTextScoreProperty();
}

    //5.BasicMongoPersistentEntity类,其实现了MongoPersistentEntity接口类,提供了用于获取集合名称的方法。其判断当前BasicMongoPersistentEntity对象的expression参数是否存在,若不存在,返回当前的collection参数,若存在则返回其getValue()的值
    public String getCollection() {
        return this.expression == null ? this.collection : (String)this.expression.getValue(this.context, String.class);
    }

    //6.我们看下BasicMongoPersistentEntity的构造方法
    public BasicMongoPersistentEntity(TypeInformation<T> typeInformation) {
        super(typeInformation, BasicMongoPersistentEntity.MongoPersistentPropertyComparator.INSTANCE);
        Class<?> rawType = typeInformation.getType();
        String fallback = MongoCollectionUtils.getPreferredCollectionName(rawType);
        this.context = new StandardEvaluationContext();
        if (this.isAnnotationPresent(Document.class)) {
            Document document = (Document)this.getRequiredAnnotation(Document.class);
            this.collection = StringUtils.hasText(document.collection()) ? document.collection() : fallback;
            this.language = StringUtils.hasText(document.language()) ? document.language() : "";
            this.expression = detectExpression(document);
        } else {
            this.collection = fallback;
            this.language = "";
            this.expression = null;
        }

    }
    //7我们主要看上面的fallback参数的生成方式
    public static String getPreferredCollectionName(Class<?> entityClass) {
        return StringUtils.uncapitalize(entityClass.getSimpleName());//传入class的名称计算出集合名称
    }

    public static String uncapitalize(String str) {
        return changeFirstCharacterCase(str, false);//设置第一个字符为小写
    }
    //根据传入字符串以及第二个元素确定字符串首字母大写还是小写
    private static String changeFirstCharacterCase(String str, boolean capitalize) {
        if (!hasLength(str)) {
            return str;
        } else {
            char baseChar = str.charAt(0);
            char updatedChar;
            if (capitalize) {
                updatedChar = Character.toUpperCase(baseChar);
            } else {
                updatedChar = Character.toLowerCase(baseChar);
            }

            if (baseChar == updatedChar) {
                return str;
            } else {
                char[] chars = str.toCharArray();
                chars[0] = updatedChar;
                return new String(chars, 0, chars.length);
            }
        }
    }

getRequiredPersistentEntity():


    //1.MappingContext类
    //该方法是MappingContext接口类的一个方法。其调用自身提供的getPersistentEntity接口,
    //将传入的接口转换成继承PersistentEntity的类E(`E extends PersistentEntity<?, P>`)
    default E getRequiredPersistentEntity(Class<?> type) throws MappingException {
        E entity = this.getPersistentEntity(type);
        if (entity != null) {
            return entity;
        } else {
            throw new MappingException(String.format("Couldn't find PersistentEntity for type %s!", type));
        }
    }

    //2.MappingContext类
    //MappingContext提供的接口类,用于将传入的类class转换成继承PersistentEntity的类E(`E extends PersistentEntity<?, P>`)
    E getPersistentEntity(Class<?> var1);

    //3.AbstractMappingContext类
    //AbstractMappingContext是MappingContext实现类。实现了上面的getPersistentEntity()接口。
    //其首先将class作为参数调用ClassTypeInformation的静态方法,将返回值强转成TypeInformation接口类,然后调用getPersistentEntity()方法
    //ClassTypeInformation继承TypeDiscoverer类,TypeDiscoverer实现TypeInformation接口类,所以下面的强转关系成立
    public E getPersistentEntity(Class<?> type) {
        return this.getPersistentEntity((TypeInformation)ClassTypeInformation.from(type));//若想查看from方法功能看下一段源码
    }

    //4.AbstractMappingContext类
    //获取当前类维持的persistentEntities 这个map中存储的key为type对应的MutablePersistentEntity对象值,
    //若persistentEntities不包含key为type的,则判断当前type是否应该写入到persistentEntities中,
    //若不应该写入,则persistentEntities 中维持一个key为type,value为空的Optional对象的数据。
    //若允许写入,则计算对应的Optional对象值,写入并返回强制转换成MutablePersistentEntity对象
    private final Map<TypeInformation<?>, Optional<E>> persistentEntities = new HashMap();//当前类的用于存储常出现的实体类的map,key是TypeInformation对象

     public E getPersistentEntity(TypeInformation<?> type) {
        Assert.notNull(type, "Type must not be null!");//判空

        try {
            this.read.lock();//锁定读取锁
            Optional<E> entity = (Optional)this.persistentEntities.get(type);//从维持的persistentEntities获取保存当前TypeInformation对象的对应的值,
            if (entity != null) {
                MutablePersistentEntity var3 = (MutablePersistentEntity)entity.orElse((Object)null);
                return var3;//如果维持的persistentEntities这个map中有当前传入文档的class这个key,获取其value值,使用orElse对value进行判空处理后,强转成MutablePersistentEntity对象。
            }
        } finally {
            this.read.unlock();//释放读取锁
        }

        if (!this.shouldCreatePersistentEntityFor(type)) {//判断当前的type是否应该写入到维持的persistentEntities中,如果不,则将persistentEntities维持一个key为type,值为空的Optional对象的数据
            try {
                this.write.lock();//锁定写入锁
                this.persistentEntities.put(type, this.NONE);
            } finally {
                this.write.unlock();//释放写入锁
            }

            return null;
        } else if (this.strict) {
            throw new MappingException("Unknown persistent entity " + type);
        } else {
            return (MutablePersistentEntity)this.addPersistentEntity(type).orElse((Object)null);//如果当前type应该写入到维持的persistentEntities这个map中,则写入,并返回当前type所对应的value值,并强转成MutablePersistentEntity对象。
        }
    }

    //5.AbstractMappingContext
    //给维持的persistentEntities这个map中添加一个key为TypeInformation对象的记录
    protected Optional<E> addPersistentEntity(TypeInformation<?> typeInformation) {
        Assert.notNull(typeInformation, "TypeInformation must not be null!");//判空

        Optional var3;
        label151: {
            try {
                this.read.lock();//锁定读取锁
                Optional<E> persistentEntity = (Optional)this.persistentEntities.get(typeInformation);//判断维持的persistentEntities这个map中是否包含key为typeInformation的值,如果包含,则直接返回,若不包含则继续执行下面代码
                if (persistentEntity == null) {
                    break label151;
                }

                var3 = persistentEntity;
            } finally {
                this.read.unlock();//释放读取锁
            }

            return var3;
        }

        Class type = typeInformation.getType();//获取typeInformation对象中的type参数(class类型,即为当初传入的文档数据类型的class,比如传入的是一个map文档,则为map.getClass())
        var3 = null;

        MutablePersistentEntity entity;
        try {
            this.write.lock();//锁定写入锁
            //根据type创建一个MutablePersistentEntity对象。
            //创建的是BasicMongoPersistentEntity对象,
            //BasicMongoPersistentEntity对象继承BasicPersistentEntity对象,
            //BasicPersistentEntity对象实现MutablePersistentEntity对象接口类
            entity = this.createPersistentEntity(typeInformation);
            //将创建的MutablePersistentEntity封装到Optional对象中,并维护到persistentEntities这个map中
            this.persistentEntities.put(typeInformation, Optional.of(entity));
            PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(type);//获取类的属性
            Map<String, PropertyDescriptor> descriptors = new HashMap();//创建用于存储PropertyDescriptor的map
            PropertyDescriptor[] var6 = pds;
            int var7 = pds.length;//获取属性数目

            for(int var8 = 0; var8 < var7; ++var8) {//对属性进行存储,key为属性的name,值为PropertyDescriptor对象
                PropertyDescriptor descriptor = var6[var8];
                descriptors.put(descriptor.getName(), descriptor);
            }

            try {
                //Invoke the given callback on all fields in the target class, going up the class hierarchy to get all declared fields
                //在给定的目标类(type)的所有字段上请求给定的回调函数(persistentPropertyCreator),向上调整类层次结构以获取所有声明的字段
                ReflectionUtils.doWithFields(type, persistentPropertyCreator, AbstractMappingContext.PersistentPropertyFilter.INSTANCE);。

                persistentPropertyCreator.addPropertiesForRemainingDescriptors();
                entity.verify();
                if (this.persistentPropertyAccessorFactory.isSupported(entity)) {
                    entity.setPersistentPropertyAccessorFactory(this.persistentPropertyAccessorFactory);
                }
            } catch (MappingException var19) {
                this.persistentEntities.remove(typeInformation);
                throw var19;
            }
        } catch (BeansException var20) {
            throw new MappingException(var20.getMessage(), var20);
        } finally {
            this.write.unlock();
        }

        if (this.applicationEventPublisher != null && entity != null) {
            this.applicationEventPublisher.publishEvent(new MappingContextEvent(this, entity));
        }

        return Optional.of(entity);
    }   

form method:

//1.ClassTypeInformation类
    //其继承TypeDiscoverer类,TypeDiscoverer实现TypeInformation接口类
    //先判空,然后调用Map的computeIfAbsent()方法,传入文档的class和一个用ClassTypeInformation的构造函数创建的ClassTypeInformation对象。
    //并将返回结果强转成ClassTypeInformation对象。

    private static final Map<Class<?>, ClassTypeInformation<?>> CACHE = new ConcurrentReferenceHashMap();

    public static <S> ClassTypeInformation<S> from(Class<S> type) {
        Assert.notNull(type, "Type must not be null!");
        return (ClassTypeInformation)CACHE.computeIfAbsent(type, (it) -> {
            return new ClassTypeInformation(type);
        });//将文档的class放入ClassTypeInformation对象中。
    }

    //2.Map类
    //如果指定的键尚未与值mappingFunction关联,则尝试使用给定的映射函数计算其值,并将其输入到此映射中。
    //也就是说该方法功能是将key(文档的class)与传入的mappingFunction是否有关联,若没有关联,则将其关联,并返回关联之后的mappingFunction对象,或新的mappingFunction对象。
    default V computeIfAbsent(K key,
            Function<? super K, ? extends V> mappingFunction) {
        Objects.requireNonNull(mappingFunction);//判空
        V v;
        if ((v = get(key)) == null) {//判断当前调用当前的方法的对象(上面的CACHE这个map)是否包含传入key(即文档的class)
            V newValue;
            if ((newValue = mappingFunction.apply(key)) != null) {//将文档的class运用apply函数(映射函数)
                put(key, newValue);
                return newValue;
            }
        }

        return v;
    }

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324818341&siteId=291194637