【MyBatis源码解析】spring-mybatis 源码解析

一。前言

人们总是一边追逐一边回味。既要研究大型分布式框架,单机的优秀框架也不能错过。

一个框架的概览,在于入口,即配置项的解析;在于描述性配置,即如何识别和管理 bean;在于代理,即被管理的 bean 被代理成有什么样行为的类。

二。重要设计

每次使用 mybatis,都会引入 mybatis-spring 包,并且设置两个bean‘,SqlSessionFactoryBean 和 MapperScanConfigurer,并且把 SqlSessionFactoryBean 当作属性配置类,注入 MapperScanConfigurer。

SqlSessionFactoryBean 主要是设置 mapper xml文件包路径和 mybatis 配置文件属性。

MapperScanConfigurer 主要是扫描 mappe 接口,把接口 bean 替换为为 MapperFactoryBean。

1.MapperScannerConfigurer.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry b)。第一步从 applicationContext 取出属性给成员变量(eg: basePackage、sqlSessionTemplateBeanName)赋值。第二步调用ClassPathMapperScanner.Scan(basePackage) 扫描 basePackage 中类文件。

2.ClassPathMapperScanner.Scan(basePackage),调用的是父类 ClassPathBeanDefinitionScanner.Scan(basePackage),父类回调子类的 doScan(basePackage)。doScan(basePackage) 第一步获取父类 Scan 扫描后的 Set 。第二步,对 BeanDefinition 进行处理,增加属性 SqlSessionFactory 和 SqlSessionTemplate 等。

3.ClassPathMapperScanner.processBeanDefinitions(beanDefinitions),即在 步骤2 doScan() 方法中调用,处理扫描 mapper 接口得到的 beanDefinition,接口是没法实例化的,所以在这个方法中,会把 beanDefinition 原有的 beanClass 属性替换为 MapperFactoryBean.class 。即 spring 最终会把扫描到的 mapper 接口实例化成这个类。

MapperFactoryBean 主要作用,提供 jdk 代理类 MapperProxy ,供运行时调用。

1。MapperFactoryBean.checkDaoConfig(),这个方法在父类 DaoSupport 实现的 InitializingBean.afterPropertiesSet() 方法中回调,这个方法主要作用,是调用 MapperRegistry.addMapper(mapperInterface), 把 mapper interface 注册到 MapperRegistry 中的 HashMap 中。

2。MapperFactoryBean 是一个工厂 bean,在调用 getObject() 时,会从 MapperRegistry 中,根据 mapper interface 取出 MapperProxyFactory,然后调用 MapperProxyFactory.newInstance() 返回 MapperProxy 实例。

3.MapperProxy 实现了 InvocationHandler,最终在 mapper interface 方法被调用时,会调用这个代理类进行具体方法的执行。

MapperProxy 维护了 Map 缓存,即每个方法都有指定的 Invoker。

1.MapperProxy 在执行 invoke(Object,Method,Object[]) 方法时,会从维护的 map 中找对应方法的 MapperMethodInvoker,然后具体的执行托给 MapperMethodInvoker。

2.Invoker 有两种,一种是 java8 之后才有的 default 方法,转为 DefaultMethodInvoker,使用 MethodHandler.bindTo(object).invokeWithArgument(args) 反射调用。一种是正常的接口方法,转为 PlainMethodInvoker ,使用 MapperMethod 进行方法的执行。

3.MapperMethod.execute(SqlSession, Object[]),增删改查都是使用参数中的 SqlSessionTemplate进行操作。

三。有意思的写法

Optional.ofNullable(param).map(Function<? super T, ? extends U>).orElse();

其中 Function 方法对象指:被 T 类型对象调用处理对象本身,返回 R 类型对象。

还有类中嵌入私有的静态内部类实现内部接口,不同的条件,使用不同的静态内部类。

四。总结

spring-mybatis 通过解析配置中的包路径,扫描路径下的文件,使用工厂 bean,让接口在运行时,有不同的表现。

你可能感兴趣的:(mybatis)