spring和mybatis整合为什么只定义了接口?为什么设置自动装配模型为BY_TYPE

背景

是不是还在疑惑为什么我们在工程中定义了接口mybatis就可以直接操作我们的数据库?
是不是想了解spring和mybaits整合的原理?
了解原理后我们能复用在工程上的东西是什么?换句话说怎么提高代码的逼格?

目的

基于上述背景,笔者准备深入源码带大家一探究竟,读完这篇文章大家可以的到的收获

  1. 了解Mybatis和Spring整合的底层原理
  2. 知道为什么只定义了接口就可以直接操作数据库
  3. 了解Spring中的拓展点和FactoryBean的使用
  4. 可以自己定义插件提高代码逼格
  5. Spring中自动装配的类型到底是什么

分析问题

准备

代码环境:

  • JDK :1.8
  • Spring Boot :2.3
  • 基于注解
  • 忽略一些不重要的细节 项目代码如下
//对象
public class AD {
   
    //id
    private int id;
    //名称
    private String name;
}
//mapper类
public interface AdMapper {
   

    @Select("select id , name  from " + " ad " + "where id=#{id} ")
    AD findADById(@Param("id") int id);
}
//接口
public interface AdService {
   
    /**
     * 通过id获取广告对象
     *
     * @param id
     * @return
     */
    AD findADbyId(int id);
}
//接口实现类
@Service
public class AdServiceImpl implements AdService {
   

    @Resource
    private AdMapper adMapper;

    @Override
    public AD findADbyId(int id) {
   
        return adMapper.findADById(id);
    }
}
//启动类
@MapperScan("com.learn.code.mybatis.mapper")
@SpringBootApplication
public class LearnCodeApplication {
   
    public static void main(String[] args) {
   
        SpringApplication.run(LearnCodeApplication.class, args);
    }
}

问题1 Mapper对象的BeanDefinition是怎么加入到工厂中的

问题由来:一个对象只有被Spring创建并且放入到工厂中才能被其他对象注入,比如AdServiceImpl就是加了@Service注解并且结合包扫描。这样环境中就会有这个对象,但是AdMapper没有加任何的注解,而我们的 AdServiceImpl却可以直接通过 @Resource注入进来。说明这个对象是被Spring创建的。

回想Spring创建Bean的过程,几乎所有的对象都是先变成BeanDefinition然后再通过工厂创建,所以我们只要找到这个Mapper类是什么时候变成BeanDefinition的。

我们通过看代码发现和Mybatis相关的只有开始在配置类中加入的注解@MapperScan,难道是这个注解起的作用吗?

没错,这个注解是个入口,就像是把钥匙,像只有我们带了钥匙才能开门一样,只有加了这个注解(注意本文基于注解配置)才能实现上述的功能

那现在我们重点看一下这个注解

@MapperScan

屏蔽掉一些非关键信息 注解结构如下:

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

  String[] value() default {
   };

  String[] basePackages() default {
   };

  Class<?>[] basePackageClasses() default {
   };
}

在这个注解类中发现其实也没有做太多事,但是我们会发现类上边有@Import(MapperScannerRegistrar.class)这行.对Spring启动源码有了解的同学可能知道,在准备工厂阶段,会把 @Import引入的类当作配置类,后期通过Spring创建这个bean。所以我们应该能感觉MapperScannerRegistrar这个类是有些作用的,照例点进去看一下源码。

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware

发现这个类继承了ImportBeanDefinitionRegistrar实现了这个接口,这个接口是Spring当中的一个扩展点,基于接口中的registerBeanDefinitions方法我们可以做到向bean工厂中注入BeanDefinition,现在看来我们的方向是对的。

下面解析一下 registerBeanDefinitions 方法

/**
* importingClassMetadata 注解元素
* registry  用来向 BeanDefinitionRegistry 加入 BeanDefinition
*/
@Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
   
	//获取MapperScan注解中的属性信息 @MapperScan("com.learn.code.mybatis.mapper")
	// 类上可能会有很多注解  这里指定名称获取 
    AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    //初始化一个 scanner 用作扫描指定包下的类
    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
    
    // Spring 3.1 版本需要有这个判断 特殊逻辑
    if (resourceLoader != null) {
   <
  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值