这一篇是紧接着上一篇文章 基于springboot的配置加载和sqlsessionFactory构造写的,这篇文章将要介绍Mapper接口的扫描和加载。
从图上可以看出这个@MapperScan注解是一个复合注解,它同时拥有了@Import(MapperSannerRegistrar), 这个是扫描非常重要的类。
可以看出该类实现了ImportBeanDefinitionRegistrar和ResourceLoaderAware, 实现ResourceLoaderAware接口,spring容器会自动注入一个resourseLoader的实现类,实现了ImportBeanDefinitionRegistrar则会自动调用registerBeanDefinitions方法,来向Spring容器注入bean, 具体可参考这篇文章 https://www.cnblogs.com/zzq-include/p/8004506.html 调试发现注入的ResourceLoader实际的实例是AnnotationConfigEmbeddedWebApplication这个类,
这个方法主要是用ClassPathMapperScanner这个类去扫描路径然后注入到Spring的容器中,前面主要在设置scan的属性,重点看一最后两行scan.registerFilter和scan.doScan.
registerFileters这个方法,可以看到这个方法中,如果我们不配置MapperScan中的annotationClass属性时,那么默认扫描的的配置包路径处理package-info类的所有的接口,接下来看下扫描类doScan做了哪些事。
执行扫描类,主要处理是在postBeanDefinitions方法中处理的,
从图中最后三行分别是在初始化注入Mapper接口类全名,设置注入spring容器的中BeanDefinition的实际BeanClass是MapperFacotyBean这个类,设置MapperFactoryBean实例对象addToConfig的值为true,
方法的后半部分都是设置beandefinition的属性,还有最重要要的是definition设置AuotWiredMode的值为AUTOWIRE_BY_TYPE,是该bean是的含有set的方法的属性会按照的类型自动装配。下面来一下MapperFactoryBean这个类,
它是继承自SqlSessionSupport这个类并实现FactoryBean这个接口,从前面介绍过这里的MapperInterface就是扫描的Mapper接口通过构造函数注入进来的
从这里看出MapperFactoryBean这个类获取的bean是通过SqlSession构造的getMapper方法得到的.
从上图看出MapperFacotoryBean的结构,在初始化这个bean会调用afoterPropertiesSet这个方法(这个是Spring的bean的生命周期的钩子方法),这个方法MapperFacotoryBean也实现了。
可以看出这个方法里,才是向Configuration中注入mapper的地方。继续看Configuration的addMapper方法。
这个方法是MybatisMapperRegistry这个类中注册mapper这个接口,那么mybatisMapperRegistry是怎么注册这个接口的,接着往下看,
上面这段截图是MybatisMapperRegistry的addMapper这个方法,实际这个类中定义了Map,key为Mpper接口的class,value是MapperProxyFacotry这个类注册接口的,MapperProxyFacotry这个类是Mapper代理的构造的工厂类。
这个就是包含的属性是接口的class,以及这个类的缓存方法。最后一个方法是 创建动态代理的方法,
可以看到MapperProxy是实现InvocationHandler这个接口,显然这里用的是JDK的实现的动态代理实现的,前面注册的时候,是注册的是MapperProxyFactory这个实例,俺么创建代理是在什么时候进行的呢?既然不是在注册的时候注入的,那么可能是调用时创建的,下面看一个getMapper这个方法
可以看到在这里 获取的MapperProxyFactory调用了调用了newInstance来创建这个代理,到这里Mapper的注册过程就基本完成了。
总结: 今天主要介绍了Mapper接口的扫描和加载接口并注册Mapper接口的代理工厂,下一篇将会介绍Mapper接口是如何通过使用动态代理来调用执行的过程. 。