mybatis-plus链式调用解析

mybatis-plus链式调用解析

mybatis-plus相信大家都不陌生,尤其在需要快速开发的时候,使用mp进行开发,确实能提高效率,在使用的过程中,一直都很好奇,mp链式调用的实现

源码解析

从最经典的LambdaQueryWrapper入手,点开源码会发现,调用的函数返回了typedThis,确实是很经典的链式的设计,所谓链式调用,就是通过设置方法的返回值,让返回值变为对象自身,从而实现连续的方法调用

java 复制代码
public class LambdaQueryWrapper<T> extends AbstractLambdaWrapper<T, LambdaQueryWrapper<T>>
    implements Query<LambdaQueryWrapper<T>, T, SFunction<T, ?>> {
	// 省略构造函数

    /**
     * SELECT 部分 SQL 设置
     *
     * @param columns 查询字段
     */
    @SafeVarargs
    @Override
    public final LambdaQueryWrapper<T> select(SFunction<T, ?>... columns) {
        if (ArrayUtils.isNotEmpty(columns)) {
            this.sqlSelect.setStringValue(columnsToString(false, columns));
        }
        return typedThis;
    }    @Override
    public LambdaQueryWrapper<T> select(Class<T> entityClass, Predicate<TableFieldInfo> predicate) {
        if (entityClass == null) {
            entityClass = getEntityClass();
        } else {
            setEntityClass(entityClass);
        }
        Assert.notNull(entityClass, "entityClass can not be null");
        this.sqlSelect.setStringValue(TableInfoHelper.getTableInfo(entityClass).chooseSelect(predicate));
        return typedThis;
    }

追踪一下typedThis,会发现来到了AbstractWrapper中,看来这里就是真正实现链式调用的地方,看到这里原谅我孤陋寡闻,确实没怎么用泛型,原来还能这么用的😂。

java 复制代码
public abstract class AbstractWrapper<T, R, Children extends AbstractWrapper<T, R, Children>> extends Wrapper<T>
    implements Compare<Children, R>, Nested<Children, Children>, Join<Children>, Func<Children, R> {

    /**
     * 占位符
     */
    protected final Children typedThis = (Children) this;
 	// 省略其余全局变量

    @Override
    public T getEntity() {
        return entity;
    }

    public Children setEntity(T entity) {
        this.entity = entity;
        return typedThis;
    }
	//普通query的R指定的String,lambda的R指定的SFunction,用来实现方法的引用
    @Override
    public Children eq(boolean condition, R column, Object val) {
        return addCondition(condition, column, EQ, val);
    }

T,R其实都是泛型占位符,但为什么还有一个R呢?查看一下AbstractWrapper的实现类,会发现正常的query指定的是string,而lambdaquery指定的是SFunction<T, ?>,看来是实现lambdaquery的方法引用。

java 复制代码
public class QueryWrapper<T> extends AbstractWrapper<T, String, QueryWrapper<T>>
    implements Query<QueryWrapper<T>, T, String> {
java 复制代码
public abstract class AbstractLambdaWrapper<T, Children extends AbstractLambdaWrapper<T, Children>>
        extends AbstractWrapper<T, SFunction<T, ?>, Children> {

那Children也是同理,是一个自引用的占位符,根据不同的子类实现,强转成不同的子类示例

自定义实现

知道了原理,就可以模仿一下mp的实现,先定义一个抽象类,业务没那么复杂,就不需要定义太多泛型,同时定义一些方法和抽象方法

java 复制代码
@Slf4j
public abstract class AbstractLambdaESignBuilder <Children extends AbstractLambdaESignBuilder<Children>>{

    /**
     * 占位符
     */
    protected final Children typedThis = (Children) this;

    public Children preview(ESignInitiateParam initiateParam){
        CreateDocTemplate createDocTemplate = new CreateDocTemplate();
        createDocTemplate.setDocTemplateId(eSignConfig.getDocTemplateId());
        createDocTemplate.setFileName(eSignConfig.getFileName());
        List<Component> components = buildDebt(initiateParam);
        createDocTemplate.setComponents(components);
        body = JSONObject.toJSONString(createDocTemplate);
        return typedThis;
    }

    public Children sortAPIUrl(String apiUrl){
        this.sortApiUrl = apiUrl;
        return typedThis;
    }

    protected abstract ESignModel get(String msg, String responseMsg);

    protected abstract Children config(ESignConfig eSignConfig);
}

子类继承一下,重写父类的方法

java 复制代码
@Slf4j
@Service
public class LambdaESignBuilder extends AbstractLambdaESignBuilder<LambdaESignBuilder> {
    @Override
    public LambdaESignBuilder config(ESignConfig eSignConfig) {
        super.eSignConfig = eSignConfig;
        return super.typedThis;
    }
}

这样就实现了一个简易的链式调用方法了

总结

总的来说,mp通过在父类定义一个自引用的泛型来实现链式调用,之后继承该父类的子类,只要重写父类定义的方法,既可实现链式调用,同时又定义了多个泛型类型,子类根据不同的业务需求,自定义方法的入参和出参。对于泛型的使用是一个很好的例子

相关推荐
小宁爱Python2 分钟前
Django 基础入门:命令、结构与核心配置全解析
后端·python·django
老华带你飞8 分钟前
考研论坛平台|考研论坛小程序系统|基于java和微信小程序的考研论坛平台小程序设计与实现(源码+数据库+文档)
java·vue.js·spring boot·考研·小程序·毕设·考研论坛平台小程序
CHEN5_0210 分钟前
leetcode-hot100 11.盛水最多容器
java·算法·leetcode
songx_9913 分钟前
leetcode18(无重复字符的最长子串)
java·算法·leetcode
你的人类朋友40 分钟前
认识一下Bcrypt哈希算法
后端·安全·程序员
tangweiguo030519871 小时前
基于 Django 与 Bootstrap 构建的现代化设备管理平台
后端·django·bootstrap
在路上`1 小时前
前端学习之后端java小白(三)-sql外键约束一对多
java·前端·学习
IT果果日记1 小时前
详解DataX开发达梦数据库插件
大数据·数据库·后端
dazhong20121 小时前
Spring Boot 项目新增 Module 完整指南
java·spring boot·后端
bobz9651 小时前
Cilium + Kubevirt 与 Kube-OVN + Kubevirt 在公有云场景下的对比与选择
后端