Spring Repository解析---以Mongo Repository为例

原创
2018/04/30 15:05
阅读数 16

摘要

Spring 为java web 开发领域提供了大量的优秀的框架,第三方包,大大解放了生产力,本文主要介绍Spring Repository在连接数据库这边做的一些封装,并以Mongo Repository为例,详细阐述下Repository实现机制,本文基于spring-data-mongo1.10.4

问题

在使用Repository的时候,相信很多人都有下面的疑问,本文就是致力于解决这些疑惑

  1. Repository 做了什么,和Template有什么区别,两者如何用

  2. Repository是如何做到写个方法名,就可以了(没有查询条件)

  3. Repository什么时候检查方法名的

  4. Repository可不可以只返回部分值,支持返回Long,String等类型吗

  5. 如何去查看实际发送给DB的语句

Repository 实现

一个根据userId找帖子的Repository方法

  
    
  
  
  1. @Repository

  2. public interface PostRepository extends MongoRepository<Post,String> {

  3.    Post findTopByUserId(Long userId);

  4. }

Bean 加载

  1. MongoRepositoryFactoryBean 继承自RepositoryFactoryBeanSupport抽象类,提供了一个afterProperties()方法,在属性被加载后,进行RepositoryFactorySupport实例的设置


  2. RepositoryFactoryBeanSupport 抽象类中的afterProperties()方法中调用initAndReturn(),然后调用getRepository()设置定义注解为@Repository的代理类。在这里即设置了PostRepository 的代理类,同时构建了Repository接口的方法,并做校验

    ResolveQuery方法中构建了PartTreeMongoQuery其中类的成员变量PartTree存储了Repository的方法,这样不用每次实际去调用方法.PartTree 将方法通过parser转换成一个主谓语,by前后语义


    1. private final PartTree.Subject subject;

    2. private final PartTree.Predicate predicate;

方法调用

  1. 实际调用方法时,在上面Bean加载时代理了QueryExecutorMethodInterceptor


    1. result.addAdvice(new RepositoryFactorySupport.QueryExecutorMethodInterceptor(information, customImplementation, target));

  2. 所以调用时,就会执行QueryExecutorMethodInterceptor.invoke方法


    1. private Object doInvoke(MethodInvocation invocation) throws Throwable {

    2.            Method method = invocation.getMethod();

    3.            Object[] arguments = invocation.getArguments();

    4.            Method actualMethod;

    5.            if(this.isCustomMethodInvocation(invocation)) {

    6.                actualMethod = this.repositoryInformation.getTargetClassMethod(method);

    7.                return this.executeMethodOn(this.customImplementation, actualMethod, arguments);

    8.            } else if(this.hasQueryFor(method)) {

    9.                // 执行RepositoryQuery.execute方法

    10.                return ((RepositoryQuery)this.queries.get(method)).execute(arguments);

    11.            } else {

    12.                actualMethod = this.repositoryInformation.getTargetClassMethod(method);

    13.                return this.executeMethodOn(this.target, actualMethod, arguments);

    14.            }

    15.        }

  3. 调用AbstractMongoQuery.execute去执行query 这个方法里包含了构建query 条件,发送查询语句的所有逻辑

    PartTreeMongoQuery.createQuery根据之前的partTree结构将查询进行数值绑定,构成真正的query。 然后执行时调用的是MongoTemplate


    1. public Object execute(Object[] parameters) {

    2.        MongoParameterAccessor accessor = new MongoParametersParameterAccessor(this.method, parameters);

    3.        // 构建query条件

    4.        Query query = this.createQuery(new ConvertingParameterAccessor(this.operations.getConverter(), accessor));

    5.        this.applyQueryMetaAttributesWhenPresent(query);

    6.        ResultProcessor processor = this.method.getResultProcessor().withDynamicProjection(accessor);

    7.        String collection = this.method.getEntityInformation().getCollectionName();

    8.        MongoQueryExecution execution = this.getExecution(query, accessor, new ResultProcessingConverter(processor, this.operations, this.instantiators));

    9.        return execution.execute(query, processor.getReturnedType().getDomainType(), collection);

    10.    }

答案

  1. Repository 做了什么,和Template有什么区别,两者如何用 答: Repository是在Template上面进行了进一步的封装,减少了重复代码。 多数据源的时候需要为repository指定具体的template


  2. Repository是如何做到写个方法名,就可以了(没有查询条件) 答: 构建一个语义化的parse


  3. Repository什么时候检查方法名的 答:Bean加载的时候


  4. Repository可不可以只返回部分值,支持返回Long,String等类型吗 答: 不可以返回部分值,PartTree没有解析返回值语句


  5. 如何去查看实际发送给DB的语句 org.springframework.data.mongodb.repository.query.MongoQueryCreator 类进行了正在的实际的query语句生成

    当然一个粗暴的方法就是开启org.springframework的debug日志


欢迎关注我的个人公众号,第一时间了解NoSQL技术


本文分享自微信公众号 - 方丈的寺院(gh_c98f244e174d)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部