直接开门见山,大多数会用mongoDB开发的都知道实体类上加上
@Document(collection = “XXX”)
可以直接将操作指定到对应的XXX 集合中,但是对应第一次玩mongoDB的我却浑然不知(留下没有技术的眼泪)。起因是因为每次调用都需要指定collectionName,如下
Long totalCount = mongoOperations.count(query, reqDTO.getClass(),"refund_error");
List<OperatorBillingSummaryPO> list = mongoOperations.find(query, OperatorBillingSummaryPO.class,"operator_billing_summary");
如果不指定collectionName则用默认的类名(等下会讲到源码)
对于处女座的我而言看着特别不舒服,很想把他们全部规整化,于是便有了以下的探索
1、方案一
首先我第一个想到的是将MongoOperations(或者MongoTemplate)在业务代码上所用到
操作(新增修改查询那些)全部用统一MongoDBUtil工具类封装,每次都通过工具类进行操作,collectionName 则通过枚举匹配,或者传入Class类的类名进行分解拆分(这种方法比较土),将RefundErrorInfoBO 转成 refund_error 类似这样,除此之外,也可以用ThreadLocal或者缓存的方式查询,因为思路比较简单就不贴代码了。
2、方案二
由于方案一不合适,直接去spring-data-mongodb的官网搜(https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongodb.mapping-usage.events),
于是发现有个生命周期事件,可通过继承 AbstractMongoEventListener 事件监听器进行事件监听,不过只能拿到event事件的实体source、事件处理后的Document以及我朝思暮想的collectionName,但并不能设置具体值,MongoMappingEvent 类如下
public class MongoMappingEvent<T> extends ApplicationEvent {
private static final long serialVersionUID = 1L;
private final @Nullable Document document;
private final @Nullable String collectionName;
/**
* Creates new {@link MongoMappingEvent}.
*
* @param source must not be {@literal null}.
* @param document can be {@literal null}.
* @param collectionName can be {@literal null}.
*/
public MongoMappingEvent(T source, @Nullable Document document, @Nullable String collectionName) {
super(source);
this.document = document;
this.collectionName = collectionName;
}
/**
* @return {@literal null} if not set.
*/
public @Nullable Document getDocument() {
return document;
}
/**
* Get the collection the event refers to.
*
* @return {@literal null} if not set.
* @since 1.8
*/
public @Nullable String getCollectionName() {
return collectionName;
}
/*
* (non-Javadoc)
* @see java.util.EventObject#getSource()
*/
@SuppressWarnings({ "unchecked" })
@Override
public T getSource() {
return (T) super.getSource();
}
}
3、方案三
最直接的方法,也就是看源码
首先从find方法入手
org.springframework.data.mongodb.core.MongoTemplate#find(org.springframework.data.mongodb.core.query.Query, java.lang.Class)
进入设置方法
org.springframework.data.mongodb.core.MongoTemplate#determineCollectionName
获取PersistentEntity
org.springframework.data.mapping.context.MappingContext#getRequiredPersistentEntity(java.lang.Class<?>)
从Debug模式进入可以看到已经获取到collection了(此时已添加@Document(collection = “refund_error”)注解)
于是返回上层的设置方法
org.springframework.data.mapping.context.AbstractMappingContext#getPersistentEntity(org.springframework.data.util.TypeInformation<?>)
entity不为空,在此退出,可以看到entity是通过AbstractMappingContext内置的HashMap常量persistentEntities获取到的
persistentEntities是怎么设置进来的呢?点击可以看到调用的put方法,在此方法下
org.springframework.data.mapping.context.AbstractMappingContext#addPersistentEntity(org.springframework.data.util.TypeInformation<?>)
entity还是被设置了,继续往上看createPersistentEntity方法
createPersistentEntity有三个实现类,看MongoMappingContext的方法
org.springframework.data.mongodb.core.mapping.MongoMappingContext#createPersistentEntity
,此时还是被设置
继续往上,终于找到了~
此方法的意思是使用给定的 TypeInformation 创建一个新的 BasicMongoPersistentEntity。如果@Document设置了collection则用设置的值,没有则将集合名称设为实体类型名,实体名则用org.springframework.data.mongodb.MongoCollectionUtils#getPreferredCollectionName获取,并将首字母大写字母转为小写。
至于org.springframework.data.mapping.context.AbstractMappingContext#addPersistentEntity(java.lang.Class<?>) 什么时候调用的,则是在SpringAOP初始化bean时,会调用初始化方法afterPropertiesSet
进而进入org.springframework.data.mapping.context.AbstractMappingContext#initialize,再调用org.springframework.data.mapping.context.AbstractMappingContext#addPersistentEntity(java.lang.Class<?>)实现整个属性的设置
思路比较简单,有疏漏的望各位大佬指点,小弟先告退了