前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >mybatis mapperScan 的解析和仿写

mybatis mapperScan 的解析和仿写

作者头像
分享干货的你
发布2021-04-06 17:05:53
6640
发布2021-04-06 17:05:53
举报
文章被收录于专栏:分享干货的你分享干货的你

之前用过springboot 整合mybatis 觉得非常神奇,那么mybatis 的mapper 是怎么加入spring 容器的呢。

这里我们下载jar 包看一下

我们先看注解包下面的,MapperScan 这个注解。

看一下注释里面的用法,要创建数据源,事务管理器,sqlsession 会话等。

这里我们主要看看,MapperScannerRegistrar , 和对应的basePackages

我们点进去看看MapperScannerRegistrar 的具体功能

核心就是注册registerBeanDefinition,BeanDefinition 就是bean 的元数据,定义java bean 的一些属性

源码的注释翻译也是这样的。也就说我们只要注册成功,也就可以使用了。

ClassPathMapperScanner,是类注册器,

里面也有两个方法,一个过滤,一个不过滤。过滤适用于自定义注解的,稍后给你们演示一下。 这里main还有核心的doscan , 就是对bean 做处理,返回一个bean 的集合

这里mabatis 用了动态代理重写了,所以他要初始化加载数据源,还要进行参数的绑定等。我们这里直接用父类的supper.doscan() 就行。

下面我们就按照他的模式仿写一下。首先定义一个枚举,

代码语言:javascript
复制
package com.msxf;



import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {

  /**
   * Base packages to scan for MyBatis interfaces. Note that only interfaces
   * with at least one method will be registered; concrete classes will be
   * ignored.
   */
  String[] basePackages() default {};

}

同理上面也有一个scanner 的注册器。

代码语言:javascript
复制
package com.msxf;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {

  private ResourceLoader resourceLoader;

  /**
   * {@inheritDoc}
   */
  @Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

    AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
    if (resourceLoader != null) {
      scanner.setResourceLoader(resourceLoader);
    }

    List<String> basePackages = new ArrayList<String>();
    for (String pkg : annoAttrs.getStringArray("basePackages")) {
      if (StringUtils.hasText(pkg)) {
        basePackages.add(pkg);
      }
    }
    scanner.addIncludeFilter(new TypeFilter() {
      @Override
      public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        return true;
      }
    });
    
    
    scanner.addExcludeFilter(new TypeFilter() {
        @Override
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
          String className = metadataReader.getClassMetadata().getClassName();
          return className.endsWith("package-info");
        }
      });
   scanner.scan(StringUtils.toStringArray(basePackages));
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void setResourceLoader(ResourceLoader resourceLoader) {
    this.resourceLoader = resourceLoader;
  }

}

这样就结束啦,在springboot 的启动类加上

在写一个接口调用一下

成功了。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-07-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 分享干货的你 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档