mybatis接口实例化过程解析

   我们平时在使用mybatis时一般只需要定义一个接口,然后编写相应的mapper.xml文件,然后即可在spring中使用@Autowired进行注入即可使用。那么mybatis是如何根据接口来创建bean的呢?
   一般我们在使用mybatis时,都会使用
   MapperScan(basePackages = {"com.xxx.rootApp.mapper"})

这样的注解来告诉程序去哪个包下面找我们定义的接口。程序会通过MapperScannerConfigurer类的postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) 方法来解析上面的注解,我们就从该方法开始去探寻mybaitis的接口实例化过程。
MapperScannerConfigurer的postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法代码如下:

@Override
  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
       ......
      ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
      ......
      scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, 
                   ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
      ......
      }

ClassPathMapperScanner继承至ClassPathBeanDefinitionScanner,我们进入到ClassPathBeanDefinitionScanner的scan(String… basePackages)方法:

  ......
   doScan(basePackages);
   ......

注意,这里调用了doScan方法是ClassPathMapperScanner类中的,并不是父类ClassPathBeanDefinitionScanner的,我们进入ClassPathMapperScanner的doScan方法,在该方法中首先再调用父类的Set beanDefinitions = super.doScan(basePackages)来获取beanDefinitions ,我们暂且不管其中的实现,先重点看processBeanDefinitions(beanDefinitions)这一行,我们看到,在processBeanDefinitions方法中有这样一行:definition.setBeanClass(this.mapperFactoryBean.getClass());然后再其上面还有一行非常显眼的注释://the mapper interface is the original class of the bean,but, the actual class of the bean is MapperFactoryBean。通过注释我们可以得知,我们实际使用的bean实际上是通过mapperFactoryBean来创建的。
MapperFactoryBean看名称就知道是一个FactoryBean,这种工厂bean模式在spring中非常常用,通过FactoryBean实现的bean是用FactoryBean的getObject()方法来注入的bean。现在我们来看MapperFactoryBean的getObject()方法:
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}

继续跟代码,可以看到getSqlSession()获取的是SqlSessionTemplate的实例,然后我们进入SqlSessionTemplate的getMapper方法:
return getConfiguration().getMapper(type, this);
继续跟代码,进入到Configuration方法的getMapper方法:return mapperRegistry.getMapper(type, sqlSession);
然后进入到MapperRegistry的getMapper方法,该方法中有这么一行mapperProxyFactory.newInstance(sqlSession);
我们跟进去,发现最终调用的是MapperProxyFactory的newInstance(MapperProxy mapperProxy)方法:
Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy)
该方法最终返回的就是我们的bean的实例
其中,最后一个参数mapperProxy是MapperProxy的实例,该类实现了InvocationHandler接口,根据java的Proxy类的说明我们知道,当我们调用代理类的方法时,实际调用的就是InvocationHandler的invoke方法,MapperProxy的invoke方法如下:
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
至此,bean的实例化基本完成。最终我们调用接口的方法时,实际执行的就是mapperMethod.execute(sqlSession, args)。
至于mybatis的时如何加载和解析配置文件并缓存各种configure和mapperMethod,就需要再单独写文章分析了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值