Spring Data Mongo DB去掉插入的_class字段分析

大致的框架是从网上找来的资源。但是遇到了两个问题:

  1. 运行代码后,MongoDB数据库没有收到改变。
    想起了在yaml中配置的mongodb参数,那些参数,data的上一层是spring,如下:
    在这里插入图片描述
    spring boot在加载这些数据时,会得到一个MongoProperties。按住Ctrl,然后点在那些值上,然后点进去后,就出来了。
    在这里插入图片描述
    该类的属性如下:
    在这里插入图片描述
    所以Spring Boot的加载过程中,会产生这样一个bean,通过注入的方式,拿到该类,便可以拿到相应的mongo db配置。再通过一定的分析,将配置信息传给自定义的MongoTemplate。

  2. 其中使用@Deprecated方法。
    这里换成了其中的没有@Deprecated的构造方法。

先给出可以忽略掉_class字段的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Configuration
public class SpringMongoConfig {

@Autowired
public MongoProperties mongoProperties;

public @Bean MongoDbFactory mongoDbFactory() throws Exception {
// MongoClientURI uri = new MongoClientURI("mongodb://"+mongoProperties.getUsername()+":"+new String(mongoProperties.getPassword())+"@"+mongoProperties.getHost()+"/"+mongoProperties.getDatabase());
return new SimpleMongoDbFactory(mongoProperties.createMongoClient(null, null), mongoProperties.getDatabase());
}

public @Bean MongoTemplate mongoTemplate() throws Exception {
//remove _class
MappingMongoConverter converter = new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory()), new MongoMappingContext());
converter.setTypeMapper(new DefaultMongoTypeMapper(null));

return new MongoTemplate(mongoDbFactory(), converter);
}
}

从源代码去分析这个过程

从save()开始:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 从MongoTemplate的save方法开始
public void save(Object objectToSave) {
Assert.notNull(objectToSave, "Object to save must not be null!");
save(objectToSave, determineEntityCollectionName(objectToSave));
}
// 获取到集合的名字后,再存储
public void save(Object objectToSave, String collectionName) {

Assert.notNull(objectToSave, "Object to save must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty!");

MongoPersistentEntity<?> mongoPersistentEntity = getPersistentEntity(objectToSave.getClass());

// No optimistic locking -> simple save
if (mongoPersistentEntity == null || !mongoPersistentEntity.hasVersionProperty()) {
doSave(collectionName, objectToSave, this.mongoConverter);
return;
}

doSaveVersioned(objectToSave, mongoPersistentEntity, collectionName);
}
// 存储的主要步骤
protected <T> void doSave(String collectionName, T objectToSave, MongoWriter<T> writer) {

maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave, collectionName));
assertUpdateableIdIfNotSet(objectToSave);
// 加上_class的语句在这里
DBObject dbDoc = toDbObject(objectToSave, writer);
// 执行词语后,debug显示的数据如下图
maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbDoc, collectionName));
Object id = saveDBObject(collectionName, dbDoc, objectToSave.getClass());

populateIdIfNecessary(objectToSave, id);
maybeEmitEvent(new AfterSaveEvent<T>(objectToSave, dbDoc, collectionName));
}

执行toDbObject(objectToSave, writer);后,debug显示的数据如下:
在这里插入图片描述
所以继续toDbObject(objectToSave, writer);里面走:
在这里插入图片描述
所以进入MappingMongoConverterwrite(final Object obj, final DBObject dbo)方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void write(final Object obj, final DBObject dbo) {

if (null == obj) {
return;
}

Class<?> entityType = obj.getClass();
boolean handledByCustomConverter = conversions.getCustomWriteTarget(entityType, DBObject.class) != null;
TypeInformation<? extends Object> type = ClassTypeInformation.from(entityType);
// typeMapper在MappingMongoConverter的构造函数中初始化
if (!handledByCustomConverter && !(dbo instanceof BasicDBList)) {
typeMapper.writeType(type, dbo);
}

Object target = obj instanceof LazyLoadingProxy ? ((LazyLoadingProxy) obj).getTarget() : obj;

writeInternal(target, dbo, type);
}

与typeMapper初始化相关的代码如下:
在这里插入图片描述
因此,打开DefaultMongoTypeMapper,找到writeType方法,但是发现并没有,所以从它的父类DefaultTypeMapper<DBObject>中找。
在这里插入图片描述
再看accessor.writeTypeTo()。这里的accessor在该类初始化的构造器中就已经被初始化,所以我们可以从继承该类的子类DefaultMongoTypeMapper中找到该类的实现,这里的accessor就是DefaultMongoTypeMapper的一个静态内部类。
在这里插入图片描述
这个时候,再回想一下之前的修改,有一种豁然开朗的感觉,哈哈。

Spring Data Mongo DB去掉插入的_class字段分析

https://eucham.me/2018/11/10/e37c525d3ae8.html

作者

遇寻

发布于

2018-11-10

更新于

2022-04-21

许可协议

评论