【开源项目】Stream-Query的入门使用和原理分析

这篇具有很好参考价值的文章主要介绍了【开源项目】Stream-Query的入门使用和原理分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

无意间发现了一个有趣的项目,Stream-Query。了解了一下其基本的功能,可以帮助开发者省去Mapper的编写。在开发中,我们会编写entity和mapper来完成业务代码,但是Stream-Query可以省去mapper,只写entity。

快速入门

实体类

@Data
public class UserInfo{

    private static final long serialVersionUID = -7219188882388819210L;

    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    private String name;
    private Integer age;
    private String email;
}

创表语句

create table user_info
(
    id   bigint auto_increment comment '主键'
        primary key,
    name varchar(20) null comment '姓名',
    age  int comment '年龄',
    email  varchar(20)  comment '邮件' 
)comment '用户信息';

配置扫描包

@EnableMybatisPlusPlugin(basePackages = "com.charles.entity.**")

插入Demo

    @GetMapping("/t1")
    public void t1() {
        UserInfo userInfo = new UserInfo();
        userInfo.setAge(12);
        userInfo.setEmail("123@qq.com");
        userInfo.setName("张三");
        UserInfo userInfo2 = new UserInfo();
        userInfo2.setAge(123);
        userInfo2.setEmail("123@qq.com");
        userInfo2.setName("李四");
        Database.saveFewSql(Arrays.asList(userInfo, userInfo2));
    }

单个查询Demo

    @GetMapping("t2")
    public void t2() {
        UserInfo userInfo = One.of(UserInfo::getId).eq(2L).query();
        System.out.println(userInfo);
    }

多个查询Demo

    @GetMapping("t3")
    public void t3() {
        QueryCondition.query(UserInfo.class)
                .in(UserInfo::getName, Lists.of("张三", "李四"));

        QueryCondition<UserInfo> wrapper =
                QueryCondition.query(UserInfo.class)
                        .in(UserInfo::getName, Lists.of("张三", "李四"));

        List<UserInfo> list = Database.list(wrapper);
        Map<Long, UserInfo> idUserMap = OneToOne.of(UserInfo::getId).eq(1L).query();
        System.out.println(list);
    }

Stream-Query通过Database,One,Many等静态方法完成查询和插入等操作。

核心原理分析

EnableMybatisPlusPlugin注入了StreamConfigurationSelector

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Inherited
@Import({StreamConfigurationSelector.class})
public @interface EnableMybatisPlusPlugin {

  /**
   * Alias for {@link #basePackages()}
   *
   * @return base packages
   */
  String[] value() default {};

  /**
   * Base packages
   *
   * @return base packages
   */
  String[] basePackages() default {};
}

StreamConfigurationSelector注入了StreamScannerRegistrar扫描注册器和StreamPluginAutoConfiguration配置类。

public class StreamConfigurationSelector implements DeferredImportSelector, Ordered {

  @Override
  public String[] selectImports(AnnotationMetadata metadata) {
    return new String[] {
      StreamScannerRegistrar.class.getName(), StreamPluginAutoConfiguration.class.getName()
    };
  }

  @Override
  public int getOrder() {
    return HIGHEST_PRECEDENCE;
  }
}

StreamScannerRegistrar注入了StreamScannerConfigurer扫描类。

public class StreamScannerRegistrar implements ImportBeanDefinitionRegistrar {

  @Override
  public void registerBeanDefinitions(
      AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    AnnotationAttributes annotationAttributes =
        AnnotationAttributes.fromMap(
            importingClassMetadata.getAnnotationAttributes(
                EnableMybatisPlusPlugin.class.getName()));
    if (Objects.isNull(annotationAttributes)) {
      return;
    }
    BeanDefinitionBuilder builder =
        BeanDefinitionBuilder.genericBeanDefinition(StreamScannerConfigurer.class);
    Set<String> basePackages = new HashSet<>();
    basePackages.addAll(
        Arrays.stream(annotationAttributes.getStringArray("value"))
            .filter(StringUtils::hasText)
            .collect(Collectors.toSet()));
    basePackages.addAll(
        Arrays.stream(annotationAttributes.getStringArray("basePackages"))
            .filter(StringUtils::hasText)
            .collect(Collectors.toSet()));
    basePackages.addAll(
        Arrays.stream(annotationAttributes.getClassArray("basePackageClasses"))
            .filter(Objects::nonNull)
            .map(ClassUtils::getPackageName)
            .collect(Collectors.toSet()));
    if (basePackages.isEmpty()) {
      basePackages.add(ClassUtils.getPackageName(importingClassMetadata.getClassName()));
      builder.addPropertyValue("emptyBasePackages", true);
    }
    builder.addPropertyValue("basePackages", basePackages);

    Set<Class<?>> classes =
        Arrays.stream(annotationAttributes.getClassArray("classes"))
            .filter(Objects::nonNull)
            .collect(Collectors.toSet());
    builder.addPropertyValue("classes", classes);

    Class<? extends Annotation> annotation = annotationAttributes.getClass("annotation");
    if (!Annotation.class.equals(annotation)) {
      builder.addPropertyValue("annotation", annotation);
    }

    Class<?> scanInterface = annotationAttributes.getClass("interfaceClass");
    if (!Class.class.equals(scanInterface)) {
      builder.addPropertyValue("interfaceClass", scanInterface);
    }

    registry.registerBeanDefinition("streamScannerConfigurer", builder.getBeanDefinition());
  }
}

StreamScannerConfigurer实现了BeanFactoryPostProcessorStreamScannerConfigurer#postProcessBeanFactory可以根据注解扫描,可以根据接口扫描,可以根据扫描包扫描。详情可见 enablemybatisplusplugin。

  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
      throws BeansException {
    defaultScanConfig();
    // 指定类
    registerEntityClasses(this.classes);
    StreamClassPathScanner scanner = new StreamClassPathScanner(false);
    scanner.setAnnotation(this.annotation);
    scanner.setInterfaceClass(this.interfaceClass);
    scanner.registerFilters();
    Set<Class<?>> classSet = scanner.scan(this.basePackages);
    registerEntityClasses(classSet);
  }

StreamPluginAutoConfiguration配置类中注入了DynamicMapperHandler

  @Bean
  @ConditionalOnMissingBean(DynamicMapperHandler.class)
  public DynamicMapperHandler dynamicMapperHandler(
      SqlSessionFactory sqlSessionFactory, StreamScannerConfigurer streamScannerConfigurer) {
    return new DynamicMapperHandler(sqlSessionFactory, streamScannerConfigurer.getEntityClasses());
  }

DynamicMapperHandler该类的作用就是根据传入的entity的列表,构建Mapper。

public class DynamicMapperHandler {

  public DynamicMapperHandler(
      SqlSessionFactory sqlSessionFactory, Collection<Class<?>> entityClassList) {
    Configuration configuration = sqlSessionFactory.getConfiguration();
    if (configuration instanceof MybatisConfiguration) {
      MybatisConfiguration mybatisConfiguration = (MybatisConfiguration) configuration;
      entityClassList.forEach(
          entityClass -> Database.buildMapper(mybatisConfiguration, entityClass));
    }
  }
}

Database#buildMapper,根据ByteBuddy来生成对应的接口实现。

  public static void buildMapper(Configuration configuration, Class<?> entityClass) {
    if (!(configuration instanceof MybatisConfiguration)) {
      throw new IllegalArgumentException("configuration must be MybatisConfiguration");
    }
    Maps.computeIfAbsent(
        ENTITY_MAPPER_CLASS_CACHE,
        entityClass,
        k -> {
          Class<?> dynamicMapper =
              new ByteBuddy()
                  .makeInterface(
                      TypeDescription.Generic.Builder.parameterizedType(IMapper.class, entityClass)
                          .build())
                  .name(
                      String.format(
                          "%s.%sMapper",
                          PluginConst.DYNAMIC_MAPPER_PREFIX, entityClass.getSimpleName()))
                  .make()
                  .load(ClassUtils.class.getClassLoader())
                  .getLoaded();
          configuration.addMapper(dynamicMapper);
          return dynamicMapper;
        });
  }

以上就是项目初始化的流程,StreamQuery帮助我们完成了根据Entity来自动生成Mapper,接下来我们分析一下StreamQuery是如何帮助我们简化使用的。

Database#saveFewSql(java.util.Collection<T>),保存操作,获取SqlSession,获取IMapper,执行saveFewSql的方法。

  public static <T> boolean saveFewSql(Collection<T> entityList) {
    return saveFewSql(entityList, PluginConst.DEFAULT_BATCH_SIZE);
  }

  public static <T> boolean saveFewSql(Collection<T> entityList, int batchSize) {
    if (CollectionUtils.isEmpty(entityList) || batchSize <= 0) {
      return false;
    }
    return execute(
        getEntityClass(entityList),
        (IMapper<T> baseMapper) ->
            entityList.size() == baseMapper.saveFewSql(entityList, batchSize));
  }

  public static <T, R, M extends BaseMapper<T>> R execute(
      Class<T> entityClass, SFunction<M, R> sFunction) {
    SqlSession sqlSession = SqlHelper.sqlSession(entityClass);
    try {
      return sFunction.apply(getMapper(entityClass, sqlSession));
    } finally {
      SqlSessionUtils.closeSqlSession(
          sqlSession, GlobalConfigUtils.currentSessionFactory(entityClass));
    }
  }

IMapper#saveFewSql,默认实现是批量拆分List,调用saveOneSql

  /**
   * 批量插入
   *
   * @param list 集合
   * @param batchSize 分割量
   * @return 是否成功
   */
  default long saveFewSql(Collection<T> list, int batchSize) {
    return Steam.of(list).splitList(batchSize).mapToLong(this::saveOneSql).sum();
  }

补充了解

One

One,返回单个实体类。通过封装Database来完成查询单个操作。

  /**
   * query.
   *
   * @return a V object
   */
  public V query() {
    return Sf.of(Database.getOne(wrapper)).mayAlso(peekConsumer).mayLet(valueOrIdentity()).get();
  }

QueryCondition

QueryCondition查询条件类,继承了LambdaQueryWrapper

也就是new LambdaQueryWrapper<UserInfo>().in(UserInfo::getName, Lists.of("张三", "李四"));等于QueryCondition<UserInfo> wrapper = QueryCondition.query(UserInfo.class).in(UserInfo::getName, Lists.of("张三", "李四"));

public class QueryCondition<T> extends LambdaQueryWrapper<T> {

  public static <T> QueryCondition<T> query(Class<T> entityClass) {
    QueryCondition<T> condition = new QueryCondition<>();
    condition.setEntityClass(entityClass);
    return condition;
  }

OneToOne

OneToOne封装了一层Stream的操作。

  public Map<K, V> query() {
    return query(HashMap::new);
  }

  /**
   * query.
   *
   * @param mapFactory a {@link java.util.function.IntFunction} object
   * @param <R> a R class
   * @return a R object
   */
  public <R extends Map<K, V>> R query(IntFunction<R> mapFactory) {
    List<T> list = Database.list(wrapper);
    return Steam.of(list)
        .parallel(isParallel)
        .peek(peekConsumer)
        .toMap(
            keyFunction,
            valueOrIdentity(),
            SerBiOp.justAfter(),
            () -> mapFactory.apply(list.size()));
  }

AsyncHelper

AsyncHelper使用

    public static void main(String[] args) {
        List<String> result = AsyncHelper.supply(() -> {
            System.out.println(Thread.currentThread().getName() + "1111");
            return "123";
        }, () -> {
            System.out.println(Thread.currentThread().getName() + "2345");
            return "456";
        });
        System.out.println(result);

    }

原理分析,可以指定拦截器和线程池,使用CompletableFuture.supplyAsync来完成异步执行。

    @SafeVarargs
    public static <T> List<T> supply(AsyncConfig asyncConfig, SerSupp<T>... suppliers) {
        AsyncInterceptor interceptor = asyncConfig.getInterceptor();
        interceptor.before();
        CompletableFuture<T>[] futures = (CompletableFuture[])Steam.of(suppliers).map((supplier) -> {
            return CompletableFuture.supplyAsync(() -> {
                return interceptor.execute(supplier);
            }, asyncConfig.getExecutor());
        }).toArray((x$0) -> {
            return new CompletableFuture[x$0];
        });
        CompletableFuture var10000 = CompletableFuture.allOf(futures);
        interceptor.getClass();
        CompletableFuture<Void> exceptionally = var10000.exceptionally(interceptor::onError);
        (() -> {
            return asyncConfig.getTimeout() == -1 ? exceptionally.get() : exceptionally.get((long)asyncConfig.getTimeout(), asyncConfig.getTimeUnit());
        }).get();
        interceptor.after();
        return Steam.of(futures).map(CompletableFuture::get).toList();
    }

【开源项目】Stream-Query的入门使用和原理分析,开源项目介绍,mybatis,源码解析,开源,python,开发语言文章来源地址https://www.toymoban.com/news/detail-652873.html

到了这里,关于【开源项目】Stream-Query的入门使用和原理分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【总目录】机器学习原理剖析、开源实战项目、全套学习指南(50篇合集)

    我为了更加的高效的学习,需要不断地输入和输出 相信不管此时的你是怀着好奇心打开这篇文章;还是偶然间刷到这篇博文;或者带有学习目的性走到这片领域,我都相信,面前的你一定会成功,因为你懂得投资和学习。学习是一个不断发展的过程,我们要用联系的眼光看待

    2023年04月08日
    浏览(30)
  • 教你在GitHub上保障开源项目安全?入门到精通

    1998年,Christine Peterson创造了 “开源软件”这个词。她解释道:“这是刻意为之,为了让其他人更容易理解这个领域”。同年,O’Reilly组织了首届“开源峰会”。 开源软件受到更多人青睐原因在于,用户对软件拥有更多的控制权因为他们可以检查代码。对于长期项目来说,开

    2024年02月03日
    浏览(30)
  • 如何入门.NET Core ? 推荐这10个优秀的开源项目!

    .NET 5马上就要发布了,还不知道这些.NET Core开源项目? 只推荐干货!当然这些开源项目都是个人或组织开发的。 1.Ant Design Blazor .NET进行客户端Web开发又一利器。 微软官方认可,微软Build2020开发者大会Blazor介绍中,提及Ant Design Pro。一图胜千言,得到微软认可是对作者最大的

    2024年02月08日
    浏览(33)
  • 【开源免费】Vue+SpringBoot打造图书管理系统,初学者入门实战项目

    作者主页 :Designer 小郑 作者简介 :3年JAVA全栈开发经验,专注JAVA技术、系统定制、远程指导,致力于企业数字化转型,CSDN博客专家,阿里云社区专家博主,蓝桥云课讲师。 文末获取源码,项目编号: S 066 。 color{red}{文末获取源码,项目编号:S066。} 文末获取源码,项目编

    2024年02月10日
    浏览(40)
  • 【开源免费】Vue+SpringBoot打造超市账单管理系统,初学者入门实战项目

    作者主页 :Designer 小郑 作者简介 :3年JAVA全栈开发经验,专注JAVA技术、系统定制、远程指导,致力于企业数字化转型,CSDN博客专家,阿里云社区专家博主,蓝桥云课讲师。 标题 说明 项目名称 超市账单管理系统 color{red}{超市账单管理系统} 超市账单管理系统 源码获取 ht

    2024年02月09日
    浏览(42)
  • Elasticsearch ES 简单查询 Query String Search 入门

    尝试了text类型排序需要特别处理下. \\\"reason\\\" : \\\"Text fields are not optimised for operations that require per-document field data like aggregations and sorting, so these operations are disabled by default. Please use a keyword field instead. Alternatively, set fielddata=true on [name] in order to load field data by uninverting the inverted index.

    2024年02月16日
    浏览(37)
  • JPA-querydsl增强工具,query-dsl-plus,现在已开源并推送到mvnrepository

    前言 约定俗成…一种接口通用的查询方法,简化开发,增强性能,让更多的精力放在更复杂的业务上。即–按照约定,将查询条件封装成string,前端随时随意更改,但是后台不用任何调整,一个查询接口就能完成绝大多数条件查询。 由于喜欢使用JPA,所以后续就接触了quer

    2024年02月12日
    浏览(28)
  • ThreadLocal的使用介绍和底层原理解析和开源框架的使用实例

    ThreadLocal是一个线程内部的数据存储类,它可以为每个线程提供独立的变量副本,不同线程间的变量无法相互访问和修改。这避免了每个线程都要维护一套独立变量的麻烦,并且也减少了线程之间不必要的数据争用。ThreadLocal适用于这样的场景:每个线程需要有自己单独的实例,而不

    2024年02月02日
    浏览(31)
  • ROS从入门到精通10-1:项目实战之智能跟随机器人原理与实现

    本专栏旨在通过对ROS的系统学习,掌握ROS底层基本分布式原理,并具有机器人建模和应用ROS进行实际项目的开发和调试的工程能力。 🚀详情:《ROS从入门到精通》 机器人是传感器网络、通信、人工智能、分布式计算、自动化等多种技术的集大成者, 机器人技术的发展水平标

    2024年02月07日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包