声明解决方案是基于Mybatis源码,进行二次开发实现。
问题领导最近跟我提了一个需求,是有关于实现类Mybatis的@Select、@Insert注解的功能。其是基于interface层面,不存在任何的接口实现类。因而在实现的过程中,首先要解决的是如何动态实现接口的实例化。其次是如何将使接口根据注解实现相应的功能。
我们先来看看Mybatis是如何实现Dao类的扫描的。MapperScannerConfigurer.java
1 | public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { |
ClassPathMapperScanner是Mybatis继承ClassPathBeanDefinitionScanner类而来的。这里对于ClassPathMapperScanner的配置参数来源于我们在使用Mybatis时的配置而来,是不是还记得在使用Mybatis的时候要配置basePackage的参数呢?
接着我们就顺着scanner.scan()
方法,进入查看一下里面的实现。
ClassPathBeanDefinitionScanner.java
1 | public int scan(String... basePackages) { |
这里关键的代码是doScan(basePackages);
,那么我们在进去看一下。可能你会看到的是Spring源码的实现方法,但这里Mybatis也实现了自己的一套,我们看一下Mybatis的实现。
ClassPathMapperScanner.java
1 | public Set<BeanDefinitionHolder> doScan(String... basePackages) { |
definition.setBeanClass(MapperFactoryBean.class);
这行代码是非常关键的一句,由于在Spring中存在两种自动实例化的方式,一种是我们常用的本身的接口实例化类进行接口实例化,还有一种就是这里的自定义实例化。而这里的setBeanClass方法就是在BeanDefinitionHolder中进行配置。在Spring进行实例化的时候进行处理。
那么我们在看一下MapperFactoryBean.class
MapperFactoryBean.java
1 | public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> { |
在该类中其实现了FactoryBean接口,看过Spring源码的人,我相信对其都有很深的印象,其在Bean的实例化中起着很重要的作用。在该类中我们要关注的是getObject方法,我们之后将动态实例化的接口对象放到Spring实例化列表中,这里就是入口,也是我们的起点。不过要特别说明的是mapperInterface的值是如何被赋值的,可能会有疑问,我们再来看看上面的ClassPathMapperScanner.java
我们在配置MapperFactoryBean.class
的上面存在一行 definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());
其在之后在Spring的PostProcessorRegistrationDelegate类的populateBean方法中进行属性配置,会将其依靠反射的方式将其注入到MapperFactoryBean.class
中。
而且definition.getPropertyValues().add
中添加的值是注入到MapperFactoryBean对象中去的。这一点需要说明一下。