Spring Data Mongo DB去掉插入的_class字段分析
大致的框架是从网上找来的资源。但是遇到了两个问题:运行代码后,MongoDB数据库没有收到改变。想起了在yaml中配置的mongodb参数,那些参数,data的上一层是spring,如下:spring boot在加载这些数据时,会得到一个MongoProperties。按住Ctrl,然后点在那些值上
大致的框架是从网上找来的资源。但是遇到了两个问题:
运行代码后,MongoDB数据库没有收到改变。 想起了在yaml中配置的mongodb参数,那些参数,data的上一层是spring,如下:

spring boot在加载这些数据时,会得到一个MongoProperties。按住Ctrl,然后点在那些值上,然后点进去后,就出来了。

该类的属性如下:

所以Spring Boot的加载过程中,会产生这样一个bean,通过注入的方式,拿到该类,便可以拿到相应的mongo db配置。再通过一定的分析,将配置信息传给自定义的MongoTemplate。
其中使用@Deprecated方法。 这里换成了其中的没有@Deprecated的构造方法。
先给出可以忽略掉_class字段的配置如下:
@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()开始:
// 从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);里面走:

所以进入MappingMongoConverter的write(final Object obj, final DBObject dbo)方法:
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的一个静态内部类。

这个时候,再回想一下之前的修改,有一种豁然开朗的感觉,哈哈。